aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/test/src/math/CMakeLists.txt6
-rw-r--r--libc/test/src/math/RemQuoTest.h144
-rw-r--r--libc/test/src/math/remquo_test.cpp80
-rw-r--r--libc/test/src/math/remquof_test.cpp80
-rw-r--r--libc/test/src/math/remquol_test.cpp86
-rw-r--r--libc/utils/FPUtil/DivisionAndRemainderOperations.h11
6 files changed, 168 insertions, 239 deletions
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 2220cef00791..cdffe737d8df 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -686,6 +686,8 @@ add_fp_unittest(
libc_math_unittests
SRCS
remquof_test.cpp
+ HDRS
+ RemQuoTest.h
DEPENDS
libc.include.math
libc.src.math.remquof
@@ -699,6 +701,8 @@ add_fp_unittest(
libc_math_unittests
SRCS
remquo_test.cpp
+ HDRS
+ RemQuoTest.h
DEPENDS
libc.include.math
libc.src.math.remquo
@@ -712,6 +716,8 @@ add_fp_unittest(
libc_math_unittests
SRCS
remquol_test.cpp
+ HDRS
+ RemQuoTest.h
DEPENDS
libc.include.math
libc.src.math.remquol
diff --git a/libc/test/src/math/RemQuoTest.h b/libc/test/src/math/RemQuoTest.h
new file mode 100644
index 000000000000..29fcdb83b6a2
--- /dev/null
+++ b/libc/test/src/math/RemQuoTest.h
@@ -0,0 +1,144 @@
+//===-- Utility class to test different flavors of remquo -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
+
+#include "utils/FPUtil/BasicOperations.h"
+#include "utils/FPUtil/FPBits.h"
+#include "utils/FPUtil/TestHelpers.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+#include <math.h>
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+template <typename T>
+class RemQuoTestTemplate : public __llvm_libc::testing::Test {
+ using FPBits = __llvm_libc::fputil::FPBits<T>;
+ using UIntType = typename FPBits::UIntType;
+
+ const T zero = __llvm_libc::fputil::FPBits<T>::zero();
+ const T negZero = __llvm_libc::fputil::FPBits<T>::negZero();
+ const T inf = __llvm_libc::fputil::FPBits<T>::inf();
+ const T negInf = __llvm_libc::fputil::FPBits<T>::negInf();
+ const T nan = __llvm_libc::fputil::FPBits<T>::buildNaN(1);
+
+public:
+ typedef T (*RemQuoFunc)(T, T, int *);
+
+ void testSpecialNumbers(RemQuoFunc func) {
+ int quotient;
+ T x, y;
+
+ y = T(1.0);
+ x = inf;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+ x = negInf;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+ x = T(1.0);
+ y = zero;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+ y = negZero;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+ y = nan;
+ x = T(1.0);
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+ y = T(1.0);
+ x = nan;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+ x = nan;
+ y = nan;
+ EXPECT_NE(isnan(func(x, y, &quotient)), 0);
+
+ x = zero;
+ y = T(1.0);
+ EXPECT_FP_EQ(func(x, y, &quotient), zero);
+
+ x = negZero;
+ y = T(1.0);
+ EXPECT_FP_EQ(func(x, y, &quotient), negZero);
+
+ x = T(1.125);
+ y = inf;
+ EXPECT_FP_EQ(func(x, y, &quotient), x);
+ EXPECT_EQ(quotient, 0);
+ }
+
+ void testEqualNumeratorAndDenominator(RemQuoFunc func) {
+ T x = T(1.125), y = T(1.125);
+ int q;
+
+ // When the remainder is zero, the standard requires it to
+ // have the same sign as x.
+
+ EXPECT_FP_EQ(func(x, y, &q), zero);
+ EXPECT_EQ(q, 1);
+
+ EXPECT_FP_EQ(func(x, -y, &q), zero);
+ EXPECT_EQ(q, -1);
+
+ EXPECT_FP_EQ(func(-x, y, &q), negZero);
+ EXPECT_EQ(q, -1);
+
+ EXPECT_FP_EQ(func(-x, -y, &q), negZero);
+ EXPECT_EQ(q, 1);
+ }
+
+ void testSubnormalRange(RemQuoFunc 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 = FPBits(v), y = FPBits(w);
+ mpfr::BinaryOutput<T> result;
+ mpfr::BinaryInput<T> input{x, y};
+ result.f = func(x, y, &result.i);
+ ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
+ }
+ }
+
+ void testNormalRange(RemQuoFunc 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 = FPBits(v), y = FPBits(w);
+ mpfr::BinaryOutput<T> result;
+ mpfr::BinaryInput<T> input{x, y};
+ result.f = func(x, y, &result.i);
+
+ // In normal range on x86 platforms, the long double implicit 1 bit can be
+ // zero making the numbers NaN. Hence we test for them separately.
+ if (isnan(x) || isnan(y)) {
+ ASSERT_NE(isnan(result.f), 0);
+ continue;
+ }
+
+ ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
+ }
+ }
+};
+
+#define LIST_REMQUO_TESTS(T, func) \
+ using RemQuoTest = RemQuoTestTemplate<T>; \
+ TEST_F(RemQuoTest, SpecialNumbers) { testSpecialNumbers(&func); } \
+ TEST_F(RemQuoTest, EqualNumeratorAndDenominator) { \
+ testEqualNumeratorAndDenominator(&func); \
+ } \
+ TEST_F(RemQuoTest, SubnormalRange) { testSubnormalRange(&func); } \
+ TEST_F(RemQuoTest, NormalRange) { testNormalRange(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H
diff --git a/libc/test/src/math/remquo_test.cpp b/libc/test/src/math/remquo_test.cpp
index 197d97069001..8efec397f39d 100644
--- a/libc/test/src/math/remquo_test.cpp
+++ b/libc/test/src/math/remquo_test.cpp
@@ -6,82 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "src/math/remquo.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
-
-using FPBits = __llvm_libc::fputil::FPBits<double>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(double)
-
-TEST(RemquoTest, SpecialNumbers) {
- int exponent;
- double x, y;
-
- y = 1.0;
- x = inf;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
- x = negInf;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
- x = 1.0;
- y = zero;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
- y = negZero;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
+#include "RemQuoTest.h"
- y = nan;
- x = 1.0;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
- y = 1.0;
- x = nan;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
- x = nan;
- y = nan;
- EXPECT_NE(isnan(__llvm_libc::remquo(x, y, &exponent)), 0);
-
- x = zero;
- y = 1.0;
- EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), zero);
-
- x = negZero;
- y = 1.0;
- EXPECT_FP_EQ(__llvm_libc::remquo(x, y, &exponent), negZero);
-}
-
-TEST(RemquoTest, SubnormalRange) {
- 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) {
- double x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<double> result;
- mpfr::BinaryInput<double> input{x, y};
- result.f = __llvm_libc::remquo(x, y, &result.i);
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
-}
+#include "src/math/remquo.h"
-TEST(RemquoTest, NormalRange) {
- 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) {
- double x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<double> result;
- mpfr::BinaryInput<double> input{x, y};
- result.f = __llvm_libc::remquo(x, y, &result.i);
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
-}
+LIST_REMQUO_TESTS(double, __llvm_libc::remquo)
diff --git a/libc/test/src/math/remquof_test.cpp b/libc/test/src/math/remquof_test.cpp
index 4ede7fb3feec..1af4ba4e0153 100644
--- a/libc/test/src/math/remquof_test.cpp
+++ b/libc/test/src/math/remquof_test.cpp
@@ -6,82 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "src/math/remquof.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
-
-using FPBits = __llvm_libc::fputil::FPBits<float>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(float)
-
-TEST(RemquofTest, SpecialNumbers) {
- int exponent;
- float x, y;
-
- y = 1.0f;
- x = inf;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
- x = negInf;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
- x = 1.0f;
- y = zero;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
- y = negZero;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
+#include "RemQuoTest.h"
- y = nan;
- x = 1.0f;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
- y = 1.0f;
- x = nan;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
- x = nan;
- y = nan;
- EXPECT_NE(isnan(__llvm_libc::remquof(x, y, &exponent)), 0);
-
- x = zero;
- y = 1.0f;
- EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), zero);
-
- x = negZero;
- y = 1.0f;
- EXPECT_FP_EQ(__llvm_libc::remquof(x, y, &exponent), negZero);
-}
-
-TEST(RemquofTest, SubnormalRange) {
- 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) {
- float x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<float> result;
- mpfr::BinaryInput<float> input{x, y};
- result.f = __llvm_libc::remquof(x, y, &result.i);
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
-}
+#include "src/math/remquof.h"
-TEST(RemquofTest, NormalRange) {
- 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) {
- float x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<float> result;
- mpfr::BinaryInput<float> input{x, y};
- result.f = __llvm_libc::remquof(x, y, &result.i);
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
-}
+LIST_REMQUO_TESTS(float, __llvm_libc::remquof)
diff --git a/libc/test/src/math/remquol_test.cpp b/libc/test/src/math/remquol_test.cpp
index 1539aabead95..e4438e83fe18 100644
--- a/libc/test/src/math/remquol_test.cpp
+++ b/libc/test/src/math/remquol_test.cpp
@@ -6,88 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "src/math/remquol.h"
-#include "utils/FPUtil/BasicOperations.h"
-#include "utils/FPUtil/FPBits.h"
-#include "utils/FPUtil/TestHelpers.h"
-#include "utils/MPFRWrapper/MPFRUtils.h"
-#include "utils/UnitTest/Test.h"
-#include <math.h>
-
-using FPBits = __llvm_libc::fputil::FPBits<long double>;
-using UIntType = FPBits::UIntType;
-
-namespace mpfr = __llvm_libc::testing::mpfr;
-
-DECLARE_SPECIAL_CONSTANTS(long double)
-
-TEST(RemquolTest, SpecialNumbers) {
- int exponent;
- long double x, y;
-
- y = 1.0l;
- x = inf;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
- x = negInf;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
- x = 1.0l;
- y = zero;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
- y = negZero;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
+#include "RemQuoTest.h"
- y = nan;
- x = 1.0l;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
- y = 1.0l;
- x = nan;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
- x = nan;
- y = nan;
- EXPECT_NE(isnan(__llvm_libc::remquol(x, y, &exponent)), 0);
-
- x = zero;
- y = 1.0l;
- EXPECT_FP_EQ(__llvm_libc::remquol(x, y, &exponent), zero);
-
- x = negZero;
- y = 1.0l;
- EXPECT_FP_EQ(__llvm_libc::remquol(x, y, &exponent), negZero);
-}
-
-TEST(RemquolTest, SubnormalRange) {
- 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) {
- long double x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<long double> result;
- mpfr::BinaryInput<long double> input{x, y};
- result.f = __llvm_libc::remquol(x, y, &result.i);
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
-}
+#include "src/math/remquol.h"
-TEST(RemquolTest, NormalRange) {
- 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) {
- long double x = FPBits(v), y = FPBits(w);
- mpfr::BinaryOutput<long double> result;
- result.f = __llvm_libc::remquol(x, y, &result.i);
- // In normal range on x86 platforms, the implicit 1 bit can be zero making
- // the numbers NaN. Hence we test for them separately.
- if (isnan(x) || isnan(y)) {
- ASSERT_NE(isnan(result.f), 0);
- } else {
- mpfr::BinaryInput<long double> input{x, y};
- ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0);
- }
- }
-}
+LIST_REMQUO_TESTS(long double, __llvm_libc::remquol)
diff --git a/libc/utils/FPUtil/DivisionAndRemainderOperations.h b/libc/utils/FPUtil/DivisionAndRemainderOperations.h
index ceae538027f3..b4732c7c5230 100644
--- a/libc/utils/FPUtil/DivisionAndRemainderOperations.h
+++ b/libc/utils/FPUtil/DivisionAndRemainderOperations.h
@@ -33,11 +33,16 @@ static inline T remquo(T x, T y, int &q) {
if (xbits.isInf() || ybits.isZero())
return FPBits<T>::buildNaN(1);
- if (xbits.isZero() || ybits.isInf()) {
+ if (xbits.isZero()) {
q = 0;
return __llvm_libc::fputil::copysign(T(0.0), x);
}
+ if (ybits.isInf()) {
+ q = 0;
+ return x;
+ }
+
bool resultSign = (xbits.sign == ybits.sign ? false : true);
// Once we know the sign of the result, we can just operate on the absolute
@@ -65,8 +70,10 @@ static inline T remquo(T x, T y, int &q) {
q |= (1 << exp);
mx = n - my;
- if (mx == 0)
+ if (mx == 0) {
+ q = resultSign ? -q : q;
return __llvm_libc::fputil::copysign(T(0.0), x);
+ }
}
NormalFloat<T> remainder(exp + normaly.exponent, mx, 0);