mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 04:27:44 +00:00
LibM: Implement nextafter() and nexttoward()
Patch from Anonymous.
This commit is contained in:
parent
e87eac9273
commit
0269578d3e
2 changed files with 186 additions and 10 deletions
|
@ -70,11 +70,14 @@ union FloatExtractor;
|
||||||
template<>
|
template<>
|
||||||
union FloatExtractor<double> {
|
union FloatExtractor<double> {
|
||||||
static const int mantissa_bits = 52;
|
static const int mantissa_bits = 52;
|
||||||
|
static const unsigned long long mantissa_max = (1ull << 52) - 1;
|
||||||
static const int exponent_bias = 1023;
|
static const int exponent_bias = 1023;
|
||||||
|
static const int exponent_bits = 11;
|
||||||
|
static const unsigned exponent_max = 2047;
|
||||||
struct {
|
struct {
|
||||||
unsigned long long mantissa : 52;
|
unsigned long long mantissa : 52;
|
||||||
unsigned exponent : 11;
|
unsigned exponent : 11;
|
||||||
int sign : 1;
|
unsigned sign : 1;
|
||||||
};
|
};
|
||||||
double d;
|
double d;
|
||||||
};
|
};
|
||||||
|
@ -82,11 +85,14 @@ union FloatExtractor<double> {
|
||||||
template<>
|
template<>
|
||||||
union FloatExtractor<float> {
|
union FloatExtractor<float> {
|
||||||
static const int mantissa_bits = 23;
|
static const int mantissa_bits = 23;
|
||||||
|
static const unsigned mantissa_max = (1 << 23) - 1;
|
||||||
static const int exponent_bias = 127;
|
static const int exponent_bias = 127;
|
||||||
|
static const int exponent_bits = 8;
|
||||||
|
static const unsigned exponent_max = 255;
|
||||||
struct {
|
struct {
|
||||||
unsigned long long mantissa : 23;
|
unsigned long long mantissa : 23;
|
||||||
unsigned exponent : 8;
|
unsigned exponent : 8;
|
||||||
int sign : 1;
|
unsigned sign : 1;
|
||||||
};
|
};
|
||||||
float d;
|
float d;
|
||||||
};
|
};
|
||||||
|
@ -152,6 +158,71 @@ static FloatType internal_to_integer(FloatType x, RoundingMode rounding_mode)
|
||||||
return extractor.d;
|
return extractor.d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is much branchier than it really needs to be
|
||||||
|
template<typename FloatType>
|
||||||
|
static FloatType internal_nextafter(FloatType x, bool up)
|
||||||
|
{
|
||||||
|
if (!isfinite(x))
|
||||||
|
return x;
|
||||||
|
using Extractor = FloatExtractor<decltype(x)>;
|
||||||
|
Extractor extractor;
|
||||||
|
extractor.d = x;
|
||||||
|
if (x == 0) {
|
||||||
|
if (!extractor.sign) {
|
||||||
|
extractor.mantissa = 1;
|
||||||
|
extractor.sign = !up;
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
if (up) {
|
||||||
|
extractor.sign = false;
|
||||||
|
extractor.mantissa = 1;
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
extractor.mantissa = 1;
|
||||||
|
extractor.sign = up != extractor.sign;
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
if (up != extractor.sign) {
|
||||||
|
extractor.mantissa++;
|
||||||
|
if (!extractor.mantissa) {
|
||||||
|
// no need to normalize the mantissa as we just hit a power
|
||||||
|
// of two.
|
||||||
|
extractor.exponent++;
|
||||||
|
if (extractor.exponent == Extractor::exponent_max) {
|
||||||
|
extractor.exponent = Extractor::exponent_max - 1;
|
||||||
|
extractor.mantissa = Extractor::mantissa_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extractor.mantissa) {
|
||||||
|
if (extractor.exponent) {
|
||||||
|
extractor.exponent--;
|
||||||
|
extractor.mantissa = Extractor::mantissa_max;
|
||||||
|
} else {
|
||||||
|
extractor.d = 0;
|
||||||
|
}
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
extractor.mantissa--;
|
||||||
|
if (extractor.mantissa != Extractor::mantissa_max)
|
||||||
|
return extractor.d;
|
||||||
|
if (extractor.exponent) {
|
||||||
|
extractor.exponent--;
|
||||||
|
// normalize
|
||||||
|
extractor.mantissa <<= 1;
|
||||||
|
} else {
|
||||||
|
if (extractor.sign) {
|
||||||
|
// Negative infinity
|
||||||
|
extractor.mantissa = 0;
|
||||||
|
extractor.exponent = Extractor::exponent_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractor.d;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
double trunc(double x) NOEXCEPT
|
double trunc(double x) NOEXCEPT
|
||||||
|
@ -634,14 +705,18 @@ double erfc(double x) NOEXCEPT
|
||||||
return 1 - erf(x);
|
return 1 - erf(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
double nextafter(double, double) NOEXCEPT
|
double nextafter(double x, double target) NOEXCEPT
|
||||||
{
|
{
|
||||||
TODO();
|
if (x == target)
|
||||||
|
return target;
|
||||||
|
return internal_nextafter(x, target >= x);
|
||||||
}
|
}
|
||||||
|
|
||||||
float nextafterf(float, float) NOEXCEPT
|
float nextafterf(float x, float target) NOEXCEPT
|
||||||
{
|
{
|
||||||
TODO();
|
if (x == target)
|
||||||
|
return target;
|
||||||
|
return internal_nextafter(x, target >= x);
|
||||||
}
|
}
|
||||||
|
|
||||||
long double nextafterl(long double, long double) NOEXCEPT
|
long double nextafterl(long double, long double) NOEXCEPT
|
||||||
|
@ -649,14 +724,18 @@ long double nextafterl(long double, long double) NOEXCEPT
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
double nexttoward(double, long double) NOEXCEPT
|
double nexttoward(double x, long double target) NOEXCEPT
|
||||||
{
|
{
|
||||||
TODO();
|
if (x == target)
|
||||||
|
return target;
|
||||||
|
return internal_nextafter(x, target >= x);
|
||||||
}
|
}
|
||||||
|
|
||||||
float nexttowardf(float, long double) NOEXCEPT
|
float nexttowardf(float x, long double target) NOEXCEPT
|
||||||
{
|
{
|
||||||
TODO();
|
if (x == target)
|
||||||
|
return target;
|
||||||
|
return internal_nextafter(x, target >= x);
|
||||||
}
|
}
|
||||||
|
|
||||||
long double nexttowardl(long double, long double) NOEXCEPT
|
long double nexttowardl(long double, long double) NOEXCEPT
|
||||||
|
|
|
@ -111,4 +111,101 @@ TEST_CASE(logarithms)
|
||||||
EXPECT_CLOSE(log10(5), 0.698988)
|
EXPECT_CLOSE(log10(5), 0.698988)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union Extractor {
|
||||||
|
explicit Extractor(double d)
|
||||||
|
: d(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Extractor(unsigned sign, unsigned exponent, unsigned long long mantissa)
|
||||||
|
: mantissa(mantissa)
|
||||||
|
, exponent(exponent)
|
||||||
|
, sign(sign)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
struct {
|
||||||
|
unsigned long long mantissa : 52;
|
||||||
|
unsigned exponent : 11;
|
||||||
|
unsigned sign : 1;
|
||||||
|
};
|
||||||
|
double d;
|
||||||
|
|
||||||
|
bool operator==(const Extractor& other) const
|
||||||
|
{
|
||||||
|
return other.sign == sign && other.exponent == exponent && other.mantissa == mantissa;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
namespace AK {
|
||||||
|
template<>
|
||||||
|
struct Formatter<Extractor> : StandardFormatter {
|
||||||
|
void format(FormatBuilder& builder, const Extractor& value)
|
||||||
|
{
|
||||||
|
builder.put_literal("{");
|
||||||
|
builder.put_u64(value.sign);
|
||||||
|
builder.put_literal(", ");
|
||||||
|
builder.put_u64(value.exponent, 16, true);
|
||||||
|
builder.put_literal(", ");
|
||||||
|
builder.put_u64(value.mantissa, 16, true);
|
||||||
|
builder.put_literal("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Extractor nextafter_translator(Extractor x, Extractor target)
|
||||||
|
{
|
||||||
|
return Extractor(nextafter(x.d, target.d));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(nextafter)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x1, 0x0), Extractor(0x0, 0x412, 0xe848000000000)), Extractor(0x0, 0x1, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x3ff, 0x0), Extractor(0x0, 0x412, 0xe848200000000)), Extractor(0x0, 0x3ff, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x0), Extractor(0x0, 0x412, 0xe848000000000)), Extractor(0x0, 0x0, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x0), Extractor(0x0, 0x412, 0xe848000000000)), Extractor(0x0, 0x0, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x3ff, 0x0), Extractor(0x0, 0x412, 0xe847e00000000)), Extractor(0x1, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x1), Extractor(0x0, 0x412, 0xe848000000000)), Extractor(0x0, 0x0, 0x2));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe848000000000), Extractor(0x0, 0x1, 0x0)), Extractor(0x0, 0x412, 0xe847fffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe848200000000), Extractor(0x0, 0x3ff, 0x0)), Extractor(0x0, 0x412, 0xe8481ffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe848000000000), Extractor(0x1, 0x0, 0x0)), Extractor(0x0, 0x412, 0xe847fffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe848000000000), Extractor(0x0, 0x0, 0x0)), Extractor(0x0, 0x412, 0xe847fffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe847e00000000), Extractor(0x1, 0x3ff, 0x0)), Extractor(0x0, 0x412, 0xe847dffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x412, 0xe848000000000), Extractor(0x0, 0x0, 0x1)), Extractor(0x0, 0x412, 0xe847fffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x1, 0x0), Extractor(0x0, 0x1, 0x0)), Extractor(0x0, 0x1, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x3ff, 0x0), Extractor(0x0, 0x3ff, 0x0)), Extractor(0x0, 0x3ff, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x0), Extractor(0x1, 0x0, 0x0)), Extractor(0x1, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x0), Extractor(0x0, 0x0, 0x0)), Extractor(0x0, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x3ff, 0x0), Extractor(0x1, 0x3ff, 0x0)), Extractor(0x1, 0x3ff, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x1), Extractor(0x0, 0x0, 0x1)), Extractor(0x0, 0x0, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x1, 0x7fe, 0xffffffffffffe));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x1, 0x0), Extractor(0x0, 0x1, 0x0)), Extractor(0x1, 0x0, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x3ff, 0x0), Extractor(0x0, 0x3ff, 0x0)), Extractor(0x1, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x0), Extractor(0x1, 0x0, 0x0)), Extractor(0x1, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x0), Extractor(0x0, 0x0, 0x0)), Extractor(0x0, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x3ff, 0x0), Extractor(0x1, 0x3ff, 0x0)), Extractor(0x0, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x1), Extractor(0x0, 0x0, 0x1)), Extractor(0x1, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x1, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xffffffffffffe));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x1, 0x0), Extractor(0x1, 0x1, 0x0)), Extractor(0x0, 0x0, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x3ff, 0x0), Extractor(0x1, 0x3ff, 0x0)), Extractor(0x0, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x0), Extractor(0x0, 0x0, 0x0)), Extractor(0x0, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x0), Extractor(0x1, 0x0, 0x0)), Extractor(0x1, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x3ff, 0x0), Extractor(0x0, 0x3ff, 0x0)), Extractor(0x1, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x1), Extractor(0x1, 0x0, 0x1)), Extractor(0x0, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x1, 0x0), Extractor(0x1, 0x419, 0x7d78400000000)), Extractor(0x0, 0x0, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x3ff, 0x0), Extractor(0x1, 0x419, 0x7d783fc000000)), Extractor(0x0, 0x3fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x0, 0x0), Extractor(0x1, 0x419, 0x7d78400000000)), Extractor(0x1, 0x0, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x0), Extractor(0x1, 0x419, 0x7d78400000000)), Extractor(0x1, 0x0, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x3ff, 0x0), Extractor(0x1, 0x419, 0x7d78404000000)), Extractor(0x1, 0x3ff, 0x1));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x0, 0x1), Extractor(0x1, 0x419, 0x7d78400000000)), Extractor(0x0, 0x0, 0x0));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x0, 0x7fe, 0xfffffffffffff), Extractor(0x0, 0x7fe, 0xfffffffffffff)), Extractor(0x0, 0x7fe, 0xfffffffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d78400000000), Extractor(0x0, 0x1, 0x0)), Extractor(0x1, 0x419, 0x7d783ffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d783fc000000), Extractor(0x0, 0x3ff, 0x0)), Extractor(0x1, 0x419, 0x7d783fbffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d78400000000), Extractor(0x1, 0x0, 0x0)), Extractor(0x1, 0x419, 0x7d783ffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d78400000000), Extractor(0x0, 0x0, 0x0)), Extractor(0x1, 0x419, 0x7d783ffffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d78404000000), Extractor(0x1, 0x3ff, 0x0)), Extractor(0x1, 0x419, 0x7d78403ffffff));
|
||||||
|
EXPECT_EQ(nextafter_translator(Extractor(0x1, 0x419, 0x7d78400000000), Extractor(0x0, 0x0, 0x1)), Extractor(0x1, 0x419, 0x7d783ffffffff));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_MAIN(Math)
|
TEST_MAIN(Math)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue