-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc][math] Fix incorrect logic in fputil::generic::add_or_sub #116129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libc Author: OverMighty (overmighty) ChangesFixes incorrect logic that went unnoticed until the function was tested Full diff: https://github.com/llvm/llvm-project/pull/116129.diff 2 Files Affected:
diff --git a/libc/src/__support/FPUtil/generic/add_sub.h b/libc/src/__support/FPUtil/generic/add_sub.h
index 6bc9dcd23bafad..5c503e752c8ecb 100644
--- a/libc/src/__support/FPUtil/generic/add_sub.h
+++ b/libc/src/__support/FPUtil/generic/add_sub.h
@@ -160,20 +160,21 @@ add_or_sub(InType x, InType y) {
} else {
InStorageType max_mant = max_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
InStorageType min_mant = min_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
- int alignment =
- max_bits.get_biased_exponent() - min_bits.get_biased_exponent();
+
+ int alignment = (max_bits.get_biased_exponent() - max_bits.is_normal()) -
+ (min_bits.get_biased_exponent() - min_bits.is_normal());
InStorageType aligned_min_mant =
min_mant >> cpp::min(alignment, RESULT_MANTISSA_LEN);
bool aligned_min_mant_sticky;
- if (alignment <= 3)
+ if (alignment <= GUARD_BITS_LEN)
aligned_min_mant_sticky = false;
- else if (alignment <= InFPBits::FRACTION_LEN + 3)
+ else if (alignment > InFPBits::FRACTION_LEN + GUARD_BITS_LEN)
+ aligned_min_mant_sticky = true;
+ else
aligned_min_mant_sticky =
(min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
- else
- aligned_min_mant_sticky = true;
InStorageType min_mant_sticky(static_cast<int>(aligned_min_mant_sticky));
@@ -183,7 +184,7 @@ add_or_sub(InType x, InType y) {
result_mant = max_mant - (aligned_min_mant | min_mant_sticky);
}
- int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;
+ int result_exp = max_bits.get_explicit_exponent() - RESULT_FRACTION_LEN;
DyadicFloat result(result_sign, result_exp, result_mant);
return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
}
diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h
index 66b188f4fa7b31..26efff4efaf948 100644
--- a/libc/test/src/math/smoke/AddTest.h
+++ b/libc/test/src/math/smoke/AddTest.h
@@ -136,6 +136,16 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
+
+ void test_mixed_normality(AddFunc func) {
+ if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() !=
+ LIBC_NAMESPACE::fputil::get_fp_type<InType>())
+ return;
+
+ EXPECT_FP_EQ(FPBits::create_value(Sign::POS, 2U, 0b1U).get_val(),
+ func(InFPBits::create_value(Sign::POS, 2U, 0U).get_val(),
+ InFPBits::create_value(Sign::POS, 2U, 0b10U).get_val()));
+ }
};
#define LIST_ADD_TESTS(OutType, InType, func) \
@@ -145,6 +155,7 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
test_invalid_operations(&func); \
} \
TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); } \
- TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }
+ TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); } \
+ TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
|
int alignment = (max_bits.get_biased_exponent() - max_bits.is_normal()) - | ||
(min_bits.get_biased_exponent() - min_bits.is_normal()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formula given in section 9.2.3.2 of Handbook of Floating-Point Arithmetic is fputil::generic::add_or_sub
, I asked myself why it wasn't just
ab73332
to
fb91e3b
Compare
fb91e3b
to
80b1add
Compare
Fixes incorrect logic that went unnoticed until the function was tested with output and input types having the same underlying floating-point format. The resulting DyadicFloat's exponent was off by one when adding two subnormal numbers, and the minimum operand's mantissa was misaligned by one bit when adding a normal number with a subnormal number.
80b1add
to
1ceafa2
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/104/builds/18422 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/188/builds/11972 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/196/builds/6132 Here is the relevant piece of the build log for the reference
|
Fixes incorrect logic that went unnoticed until the function was tested
with output and input types that have the same underlying floating-point
format.