diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -150,7 +150,7 @@ return abs(y); } - if (x >= y) { + if (abs(x) >= abs(y)) { a_exp = x_bits.getUnbiasedExponent(); a_mant = x_bits.getMantissa(); b_exp = y_bits.getUnbiasedExponent(); @@ -178,10 +178,13 @@ y_mant_width = MantissaWidth::value + 1; } else { leading_one = internal::findLeadingOne(a_mant, y_mant_width); + a_exp = 1; } if (b_exp != 0) { b_mant |= one; + } else { + b_exp = 1; } a_mant_sq = static_cast(a_mant) * a_mant; diff --git a/libc/test/src/math/HypotTest.h b/libc/test/src/math/HypotTest.h --- a/libc/test/src/math/HypotTest.h +++ b/libc/test/src/math/HypotTest.h @@ -47,28 +47,47 @@ void testSubnormalRange(Func func) { constexpr UIntType count = 1000001; - constexpr UIntType step = - (FPBits::maxSubnormal - FPBits::minSubnormal) / count; - for (UIntType v = FPBits::minSubnormal, w = FPBits::maxSubnormal; - v <= FPBits::maxSubnormal && w >= FPBits::minSubnormal; - v += step, w -= step) { - T x = T(FPBits(v)), y = T(FPBits(w)); - T result = func(x, y); - mpfr::BinaryInput input{x, y}; - ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + for (unsigned scale = 0; scale < 4; ++scale) { + UIntType maxValue = FPBits::maxSubnormal << scale; + UIntType step = (maxValue - FPBits::minSubnormal) / count; + for (int signs = 0; signs < 4; ++signs) { + for (UIntType v = FPBits::minSubnormal, w = maxValue; + v <= maxValue && w >= FPBits::minSubnormal; v += step, w -= step) { + T x = T(FPBits(v)), y = T(FPBits(w)); + if (signs % 2 == 1) { + x = -x; + } + if (signs >= 2) { + y = -y; + } + + T result = func(x, y); + mpfr::BinaryInput input{x, y}; + ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + } + } } } void testNormalRange(Func func) { constexpr UIntType count = 1000001; constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count; - for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal; - v <= FPBits::maxNormal && w >= FPBits::minNormal; - v += step, w -= step) { - T x = T(FPBits(v)), y = T(FPBits(w)); - T result = func(x, y); - mpfr::BinaryInput input{x, y}; - ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + for (int signs = 0; signs < 4; ++signs) { + for (UIntType v = FPBits::minNormal, w = FPBits::maxNormal; + v <= FPBits::maxNormal && w >= FPBits::minNormal; + v += step, w -= step) { + T x = T(FPBits(v)), y = T(FPBits(w)); + if (signs % 2 == 1) { + x = -x; + } + if (signs >= 2) { + y = -y; + } + + T result = func(x, y); + mpfr::BinaryInput input{x, y}; + ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + } } } }; diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -312,11 +312,18 @@ int thisExponent = fputil::FPBits(thisAsT).getExponent(); int inputExponent = fputil::FPBits(input).getExponent(); + if (fputil::FPBits(thisAsT).getUnbiasedExponent() == 0) + ++thisExponent; + if (fputil::FPBits(input).getUnbiasedExponent() == 0) + ++inputExponent; + if (thisAsT * input < 0 || thisExponent == inputExponent) { MPFRNumber inputMPFR(input); mpfr_sub(inputMPFR.value, value, inputMPFR.value, MPFR_RNDN); mpfr_abs(inputMPFR.value, inputMPFR.value, MPFR_RNDN); - mpfr_mul_2si(inputMPFR.value, inputMPFR.value, -thisExponent, MPFR_RNDN); + mpfr_mul_2si(inputMPFR.value, inputMPFR.value, + -thisExponent + int(fputil::MantissaWidth::value), + MPFR_RNDN); return inputMPFR.as(); } @@ -329,6 +336,10 @@ T max = thisAsT > input ? thisAsT : input; int minExponent = fputil::FPBits(min).getExponent(); int maxExponent = fputil::FPBits(max).getExponent(); + if (fputil::FPBits(min).getUnbiasedExponent() == 0) + ++minExponent; + if (fputil::FPBits(max).getUnbiasedExponent() == 0) + ++maxExponent; MPFRNumber minMPFR(min); MPFRNumber maxMPFR(max); @@ -337,10 +348,14 @@ mpfr_mul_2si(pivot.value, pivot.value, maxExponent, MPFR_RNDN); mpfr_sub(minMPFR.value, pivot.value, minMPFR.value, MPFR_RNDN); - mpfr_mul_2si(minMPFR.value, minMPFR.value, -minExponent, MPFR_RNDN); + mpfr_mul_2si(minMPFR.value, minMPFR.value, + -minExponent + int(fputil::MantissaWidth::value), + MPFR_RNDN); mpfr_sub(maxMPFR.value, maxMPFR.value, pivot.value, MPFR_RNDN); - mpfr_mul_2si(maxMPFR.value, maxMPFR.value, -maxExponent, MPFR_RNDN); + mpfr_mul_2si(maxMPFR.value, maxMPFR.value, + -maxExponent + int(fputil::MantissaWidth::value), + MPFR_RNDN); mpfr_add(minMPFR.value, minMPFR.value, maxMPFR.value, MPFR_RNDN); return minMPFR.as();