From d8ee3839e41a0c22725a5dac1d6271a7275245f5 Mon Sep 17 00:00:00 2001 From: sin-ack Date: Sat, 1 Jan 2022 17:21:01 +0000 Subject: [PATCH] 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 --- Userland/Libraries/LibM/math.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Userland/Libraries/LibM/math.cpp b/Userland/Libraries/LibM/math.cpp index b0a3459064..7c714fda28 100644 --- a/Userland/Libraries/LibM/math.cpp +++ b/Userland/Libraries/LibM/math.cpp @@ -113,49 +113,56 @@ static FloatType internal_to_integer(FloatType x, RoundingMode rounding_mode) { if (!isfinite(x)) return x; + using Extractor = FloatExtractor; Extractor extractor; extractor.d = x; + 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) { // it was easier to special case [0..1) as it saves us from // handling subnormals, underflows, etc 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.exponent = 0; } else { if (unbiased_exponent >= Extractor::mantissa_bits) return x; + auto dead_bitcount = Extractor::mantissa_bits - unbiased_exponent; auto dead_mask = (1ull << dead_bitcount) - 1; auto dead_bits = extractor.mantissa & dead_mask; extractor.mantissa &= ~dead_mask; - auto guard_mask = dead_mask >> 1; - guard = (dead_bits & guard_mask) != 0; - round = (dead_bits & ~guard_mask) != 0; + auto nonhalf_fraction_mask = dead_mask >> 1; + has_nonhalf_fraction = (dead_bits & nonhalf_fraction_mask) != 0; + has_half_fraction = (dead_bits & ~nonhalf_fraction_mask) != 0; } + bool should_round = false; switch (rounding_mode) { case RoundingMode::ToEven: - should_round = round; + should_round = has_half_fraction; break; case RoundingMode::Up: if (!extractor.sign) - should_round = guard || round; + should_round = has_nonhalf_fraction || has_half_fraction; break; case RoundingMode::Down: if (extractor.sign) - should_round = guard || round; + should_round = has_nonhalf_fraction || has_half_fraction; break; case RoundingMode::ToZero: break; } + if (should_round) { // We could do this ourselves, but this saves us from manually // handling overflow.