From 19c3894f9436ef68f33f80ee1fd589166267b5a1 Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Wed, 18 Nov 2020 21:30:47 -0800 Subject: [libc] Fix couple of corner cases in remquo. These two cases are fixed: 1. If numerator is not zero and denominator is infinity, then the numerator is returned as the remainder. 2. If numerator and denominator are equal in magnitude, then quotient with the right sign is returned. The differet tests of remquo, remquof and remquol have been unified into a single file to avoid duplication. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D92353 --- libc/test/src/math/CMakeLists.txt | 6 ++ libc/test/src/math/RemQuoTest.h | 144 ++++++++++++++++++++++++++++++++++++ libc/test/src/math/remquo_test.cpp | 80 +------------------- libc/test/src/math/remquof_test.cpp | 80 +------------------- libc/test/src/math/remquol_test.cpp | 86 +-------------------- 5 files changed, 159 insertions(+), 237 deletions(-) create mode 100644 libc/test/src/math/RemQuoTest.h (limited to 'libc/test') 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 + +namespace mpfr = __llvm_libc::testing::mpfr; + +template +class RemQuoTestTemplate : public __llvm_libc::testing::Test { + using FPBits = __llvm_libc::fputil::FPBits; + using UIntType = typename FPBits::UIntType; + + const T zero = __llvm_libc::fputil::FPBits::zero(); + const T negZero = __llvm_libc::fputil::FPBits::negZero(); + const T inf = __llvm_libc::fputil::FPBits::inf(); + const T negInf = __llvm_libc::fputil::FPBits::negInf(); + const T nan = __llvm_libc::fputil::FPBits::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, "ient)), 0); + x = negInf; + EXPECT_NE(isnan(func(x, y, "ient)), 0); + + x = T(1.0); + y = zero; + EXPECT_NE(isnan(func(x, y, "ient)), 0); + y = negZero; + EXPECT_NE(isnan(func(x, y, "ient)), 0); + + y = nan; + x = T(1.0); + EXPECT_NE(isnan(func(x, y, "ient)), 0); + + y = T(1.0); + x = nan; + EXPECT_NE(isnan(func(x, y, "ient)), 0); + + x = nan; + y = nan; + EXPECT_NE(isnan(func(x, y, "ient)), 0); + + x = zero; + y = T(1.0); + EXPECT_FP_EQ(func(x, y, "ient), zero); + + x = negZero; + y = T(1.0); + EXPECT_FP_EQ(func(x, y, "ient), negZero); + + x = T(1.125); + y = inf; + EXPECT_FP_EQ(func(x, y, "ient), 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 result; + mpfr::BinaryInput 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 result; + mpfr::BinaryInput 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; \ + 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 - -using FPBits = __llvm_libc::fputil::FPBits; -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 result; - mpfr::BinaryInput 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 result; - mpfr::BinaryInput 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 - -using FPBits = __llvm_libc::fputil::FPBits; -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 result; - mpfr::BinaryInput 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 result; - mpfr::BinaryInput 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 - -using FPBits = __llvm_libc::fputil::FPBits; -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 result; - mpfr::BinaryInput 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 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 input{x, y}; - ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0); - } - } -} +LIST_REMQUO_TESTS(long double, __llvm_libc::remquol) -- cgit v1.2.3