[libc] Return correct values for hypot when overflowed.

Hypot incorrectly returns +Inf when overflowed with FE_DOWNWARD and
FE_TOWARDZERO rounding modes.

Reviewed By: sivachandra, zimmermann6

Differential Revision: https://reviews.llvm.org/D133370
This commit is contained in:
Tue Ly
2022-09-06 14:18:18 -04:00
parent a002fd6678
commit bb6966aa53
2 changed files with 32 additions and 12 deletions

View File

@@ -189,7 +189,10 @@ static inline T hypot(T x, T y) {
sum >>= 2;
++out_exp;
if (out_exp >= FPBits_t::MAX_EXPONENT) {
return T(FPBits_t::inf());
if (int round_mode = get_round();
round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
return T(FPBits_t::inf());
return T(FPBits_t(FPBits_t::MAX_NORMAL));
}
} else {
// For denormal result, we simply move the leading bit of the result to
@@ -227,7 +230,8 @@ static inline T hypot(T x, T y) {
y_new >>= 1;
// Round to the nearest, tie to even.
switch (get_round()) {
int round_mode = get_round();
switch (round_mode) {
case FE_TONEAREST:
// Round to nearest, ties to even
if (round_bit && (lsb || sticky_bits || (r != 0)))
@@ -243,7 +247,9 @@ static inline T hypot(T x, T y) {
y_new -= ONE >> 1;
++out_exp;
if (out_exp >= FPBits_t::MAX_EXPONENT) {
return T(FPBits_t::inf());
if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
return T(FPBits_t::inf());
return T(FPBits_t(FPBits_t::MAX_NORMAL));
}
}

View File

@@ -24,24 +24,38 @@ private:
using Func = T (*)(T, T);
using FPBits = __llvm_libc::fputil::FPBits<T>;
using UIntType = typename FPBits::UIntType;
const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
const T zero = T(__llvm_libc::fputil::FPBits<T>::zero());
const T neg_zero = T(__llvm_libc::fputil::FPBits<T>::neg_zero());
const T nan = T(FPBits::build_nan(1));
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T max_normal = T(FPBits(FPBits::MAX_NORMAL));
const T min_normal = T(FPBits(FPBits::MIN_NORMAL));
const T max_subnormal = T(FPBits(FPBits::MAX_SUBNORMAL));
const T min_subnormal = T(FPBits(FPBits::MIN_SUBNORMAL));
public:
void test_special_numbers(Func func) {
constexpr int N = 13;
const T SpecialInputs[N] = {inf, neg_inf, zero,
neg_zero, max_normal, min_normal,
max_subnormal, min_subnormal, -max_normal,
-min_normal, -max_subnormal, -min_subnormal};
EXPECT_FP_EQ(func(inf, nan), inf);
EXPECT_FP_EQ(func(nan, neg_inf), inf);
EXPECT_FP_EQ(func(zero, inf), inf);
EXPECT_FP_EQ(func(neg_inf, neg_zero), inf);
EXPECT_FP_EQ(func(nan, nan), nan);
EXPECT_FP_EQ(func(nan, zero), nan);
EXPECT_FP_EQ(func(neg_zero, nan), nan);
EXPECT_FP_EQ(func(neg_zero, zero), zero);
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
mpfr::BinaryInput<T> input{SpecialInputs[i], SpecialInputs[j]};
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Hypot, input,
func(SpecialInputs[i], SpecialInputs[j]),
0.5);
}
}
}
void test_subnormal_range(Func func) {