1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:27:43 +00:00

LibM: Count fractions when exponent < -1 with mantissa == 0

Without this change, floor(-0.125) returned 0.
This is because the number has a fraction part even if mantissa is zero
while the unbiased exponent is negative.

The names of some variables were also made clearer.

Co-Authored-By: Daniel Bertalan <dani@danielbertalan.dev>
This commit is contained in:
sin-ack 2022-01-01 17:21:01 +00:00 committed by Ali Mohammad Pur
parent 2de7f2021d
commit d8ee3839e4

View file

@ -113,49 +113,56 @@ static FloatType internal_to_integer(FloatType x, RoundingMode rounding_mode)
{ {
if (!isfinite(x)) if (!isfinite(x))
return x; return x;
using Extractor = FloatExtractor<decltype(x)>; using Extractor = FloatExtractor<decltype(x)>;
Extractor extractor; Extractor extractor;
extractor.d = x; extractor.d = x;
auto unbiased_exponent = extractor.exponent - Extractor::exponent_bias; auto unbiased_exponent = extractor.exponent - Extractor::exponent_bias;
bool round = false;
bool guard = false; bool has_half_fraction = false;
bool has_nonhalf_fraction = false;
if (unbiased_exponent < 0) { if (unbiased_exponent < 0) {
// it was easier to special case [0..1) as it saves us from // it was easier to special case [0..1) as it saves us from
// handling subnormals, underflows, etc // handling subnormals, underflows, etc
if (unbiased_exponent == -1) { if (unbiased_exponent == -1) {
round = true; has_half_fraction = true;
} }
guard = extractor.mantissa != 0;
has_nonhalf_fraction = unbiased_exponent < -1 || extractor.mantissa != 0;
extractor.mantissa = 0; extractor.mantissa = 0;
extractor.exponent = 0; extractor.exponent = 0;
} else { } else {
if (unbiased_exponent >= Extractor::mantissa_bits) if (unbiased_exponent >= Extractor::mantissa_bits)
return x; return x;
auto dead_bitcount = Extractor::mantissa_bits - unbiased_exponent; auto dead_bitcount = Extractor::mantissa_bits - unbiased_exponent;
auto dead_mask = (1ull << dead_bitcount) - 1; auto dead_mask = (1ull << dead_bitcount) - 1;
auto dead_bits = extractor.mantissa & dead_mask; auto dead_bits = extractor.mantissa & dead_mask;
extractor.mantissa &= ~dead_mask; extractor.mantissa &= ~dead_mask;
auto guard_mask = dead_mask >> 1; auto nonhalf_fraction_mask = dead_mask >> 1;
guard = (dead_bits & guard_mask) != 0; has_nonhalf_fraction = (dead_bits & nonhalf_fraction_mask) != 0;
round = (dead_bits & ~guard_mask) != 0; has_half_fraction = (dead_bits & ~nonhalf_fraction_mask) != 0;
} }
bool should_round = false; bool should_round = false;
switch (rounding_mode) { switch (rounding_mode) {
case RoundingMode::ToEven: case RoundingMode::ToEven:
should_round = round; should_round = has_half_fraction;
break; break;
case RoundingMode::Up: case RoundingMode::Up:
if (!extractor.sign) if (!extractor.sign)
should_round = guard || round; should_round = has_nonhalf_fraction || has_half_fraction;
break; break;
case RoundingMode::Down: case RoundingMode::Down:
if (extractor.sign) if (extractor.sign)
should_round = guard || round; should_round = has_nonhalf_fraction || has_half_fraction;
break; break;
case RoundingMode::ToZero: case RoundingMode::ToZero:
break; break;
} }
if (should_round) { if (should_round) {
// We could do this ourselves, but this saves us from manually // We could do this ourselves, but this saves us from manually
// handling overflow. // handling overflow.