| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //===-- Unittests for remquo ----------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "include/math.h" | ||
| #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" | ||
|
|
||
| using FPBits = __llvm_libc::fputil::FPBits<double>; | ||
| using UIntType = FPBits::UIntType; | ||
|
|
||
| namespace mpfr = __llvm_libc::testing::mpfr; | ||
|
|
||
| static const float zero = FPBits::zero(); | ||
| static const float negZero = FPBits::negZero(); | ||
| static const float nan = FPBits::buildNaN(1); | ||
| static const float inf = FPBits::inf(); | ||
| static const float negInf = FPBits::negInf(); | ||
|
|
||
| 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); | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //===-- Unittests for remquof ---------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "include/math.h" | ||
| #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" | ||
|
|
||
| using FPBits = __llvm_libc::fputil::FPBits<float>; | ||
| using UIntType = FPBits::UIntType; | ||
|
|
||
| namespace mpfr = __llvm_libc::testing::mpfr; | ||
|
|
||
| static const float zero = FPBits::zero(); | ||
| static const float negZero = FPBits::negZero(); | ||
| static const float nan = FPBits::buildNaN(1); | ||
| static const float inf = FPBits::inf(); | ||
| static const float negInf = FPBits::negInf(); | ||
|
|
||
| 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); | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
|
|
||
| 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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| //===-- Unittests for remquol ---------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "include/math.h" | ||
| #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" | ||
|
|
||
| using FPBits = __llvm_libc::fputil::FPBits<long double>; | ||
| using UIntType = FPBits::UIntType; | ||
|
|
||
| namespace mpfr = __llvm_libc::testing::mpfr; | ||
|
|
||
| static const long double zero = FPBits::zero(); | ||
| static const long double negZero = FPBits::negZero(); | ||
| static const long double nan = FPBits::buildNaN(1); | ||
| static const long double inf = FPBits::inf(); | ||
| static const long double negInf = FPBits::negInf(); | ||
|
|
||
| TEST(RemquoTest, 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); | ||
|
|
||
| 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(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) { | ||
| 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); | ||
| } | ||
| } | ||
|
|
||
| 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) { | ||
| 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); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| //===-- Floating point divsion and remainder operations ---------*- 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_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H | ||
| #define LLVM_LIBC_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H | ||
|
|
||
| #include "FPBits.h" | ||
| #include "ManipulationFunctions.h" | ||
| #include "NormalFloat.h" | ||
|
|
||
| #include "utils/CPP/TypeTraits.h" | ||
|
|
||
| namespace __llvm_libc { | ||
| namespace fputil { | ||
|
|
||
| static constexpr int quotientLSBBits = 3; | ||
|
|
||
| // The implementation is a bit-by-bit algorithm which uses integer division | ||
| // to evaluate the quotient and remainder. | ||
| template <typename T, | ||
| cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> | ||
| static inline T remquo(T x, T y, int &q) { | ||
| FPBits<T> xbits(x), ybits(y); | ||
| if (xbits.isNaN()) | ||
| return x; | ||
| if (ybits.isNaN()) | ||
| return y; | ||
| if (xbits.isInf() || ybits.isZero()) | ||
| return FPBits<T>::buildNaN(1); | ||
|
|
||
| if (xbits.isZero() || ybits.isInf()) { | ||
| q = 0; | ||
| return __llvm_libc::fputil::copysign(T(0.0), x); | ||
| } | ||
|
|
||
| bool resultSign = (xbits.sign == ybits.sign ? false : true); | ||
|
|
||
| // Once we know the sign of the result, we can just operate on the absolute | ||
| // values. The correct sign can be applied to the result after the result | ||
| // is evaluated. | ||
| xbits.sign = ybits.sign = 0; | ||
|
|
||
| NormalFloat<T> normalx(xbits), normaly(ybits); | ||
| int exp = normalx.exponent - normaly.exponent; | ||
| typename NormalFloat<T>::UIntType mx = normalx.mantissa, | ||
| my = normaly.mantissa; | ||
|
|
||
| q = 0; | ||
| while (exp >= 0) { | ||
| unsigned shiftCount = 0; | ||
| typename NormalFloat<T>::UIntType n = mx; | ||
| for (shiftCount = 0; n < my; n <<= 1, ++shiftCount) | ||
| ; | ||
|
|
||
| if (static_cast<int>(shiftCount) > exp) | ||
| break; | ||
|
|
||
| exp -= shiftCount; | ||
| if (0 <= exp && exp < quotientLSBBits) | ||
| q |= (1 << exp); | ||
|
|
||
| mx = n - my; | ||
| if (mx == 0) | ||
| return __llvm_libc::fputil::copysign(T(0.0), x); | ||
| } | ||
|
|
||
| NormalFloat<T> remainder(exp + normaly.exponent, mx, 0); | ||
|
|
||
| // Since NormalFloat to native type conversion is a truncation operation | ||
| // currently, the remainder value in the native type is correct as is. | ||
| // However, if NormalFloat to native type conversion is updated in future, | ||
| // then the conversion to native remainder value should be updated | ||
| // appropriately and some directed tests added. | ||
| T nativeRemainder(remainder); | ||
| T absy = T(ybits); | ||
| int cmp = remainder.mul2(1).cmp(normaly); | ||
| if (cmp > 0) { | ||
| q = q + 1; | ||
| if (x >= T(0.0)) | ||
| nativeRemainder = nativeRemainder - absy; | ||
| else | ||
| nativeRemainder = absy - nativeRemainder; | ||
| } else if (cmp == 0) { | ||
| if (q & 1) { | ||
| q += 1; | ||
| if (x >= T(0.0)) | ||
| nativeRemainder = -nativeRemainder; | ||
| } else { | ||
| if (x < T(0.0)) | ||
| nativeRemainder = -nativeRemainder; | ||
| } | ||
| } else { | ||
| if (x < T(0.0)) | ||
| nativeRemainder = -nativeRemainder; | ||
| } | ||
|
|
||
| q = resultSign ? -q : q; | ||
| if (nativeRemainder == T(0.0)) | ||
| return __llvm_libc::fputil::copysign(T(0.0), x); | ||
| return nativeRemainder; | ||
| } | ||
|
|
||
| } // namespace fputil | ||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H |