diff options
author | Siva Chandra Reddy <sivachandra@google.com> | 2020-11-04 22:34:06 -0800 |
---|---|---|
committer | Siva Chandra Reddy <sivachandra@google.com> | 2020-11-17 15:05:42 -0800 |
commit | bb8f2585c6eab263916757435d71df16d92de4a8 (patch) | |
tree | bd25a7a2c34efd674443745930af4265e2559f00 /libc/test | |
parent | 8e923ec2a803d54154aaa0079c1cfcf146b7a22f (diff) | |
download | llvm-project-bb8f2585c6eab263916757435d71df16d92de4a8.tar.gz |
[libc] Add implementations of ldexp[f|l].
The rounding behavior of NormalFloat to float format has been changed
to round to nearest. Also, a bug in NormalFloat to subnormal number
conversion has been fixed.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D91591
Diffstat (limited to 'libc/test')
-rw-r--r-- | libc/test/src/math/CMakeLists.txt | 42 | ||||
-rw-r--r-- | libc/test/src/math/LdExpTest.h | 131 | ||||
-rw-r--r-- | libc/test/src/math/ldexp_test.cpp | 21 | ||||
-rw-r--r-- | libc/test/src/math/ldexpf_test.cpp | 21 | ||||
-rw-r--r-- | libc/test/src/math/ldexpl_test.cpp | 21 |
5 files changed, 236 insertions, 0 deletions
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 0f5405cb3a26..2220cef00791 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -413,6 +413,48 @@ add_fp_unittest( ) add_fp_unittest( + ldexp_test + SUITE + libc_math_unittests + SRCS + ldexp_test.cpp + HDRS + LdExpTest.h + DEPENDS + libc.include.math + libc.src.math.ldexp + libc.utils.FPUtil.fputil +) + +add_fp_unittest( + ldexpf_test + SUITE + libc_math_unittests + SRCS + ldexpf_test.cpp + HDRS + LdExpTest.h + DEPENDS + libc.include.math + libc.src.math.ldexpf + libc.utils.FPUtil.fputil +) + +add_fp_unittest( + ldexpl_test + SUITE + libc_math_unittests + SRCS + ldexpl_test.cpp + HDRS + LdExpTest.h + DEPENDS + libc.include.math + libc.src.math.ldexpl + libc.utils.FPUtil.fputil +) + +add_fp_unittest( logb_test SUITE libc_math_unittests diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h new file mode 100644 index 000000000000..e1976d8714f5 --- /dev/null +++ b/libc/test/src/math/LdExpTest.h @@ -0,0 +1,131 @@ +//===-- Utility class to test different flavors of ldexp --------*- 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_LDEXPTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H + +#include "utils/FPUtil/FPBits.h" +#include "utils/FPUtil/NormalFloat.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/UnitTest/Test.h" + +#include <limits.h> +#include <math.h> +#include <stdint.h> + +template <typename T> +class LdExpTestTemplate : public __llvm_libc::testing::Test { + using FPBits = __llvm_libc::fputil::FPBits<T>; + using NormalFloat = __llvm_libc::fputil::NormalFloat<T>; + using UIntType = typename FPBits::UIntType; + static constexpr UIntType mantissaWidth = + __llvm_libc::fputil::MantissaWidth<T>::value; + // A normalized mantissa to be used with tests. + static constexpr UIntType mantissa = NormalFloat::one + 0x1234; + + 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 (*LdExpFunc)(T, int); + + void testSpecialNumbers(LdExpFunc func) { + int expArray[5] = {-INT_MAX - 1, -10, 0, 10, INT_MAX}; + for (int exp : expArray) { + ASSERT_FP_EQ(zero, func(zero, exp)); + ASSERT_FP_EQ(negZero, func(negZero, exp)); + ASSERT_FP_EQ(inf, func(inf, exp)); + ASSERT_FP_EQ(negInf, func(negInf, exp)); + ASSERT_NE(isnan(func(nan, exp)), 0); + } + } + + void testPowersOfTwo(LdExpFunc func) { + int32_t expArray[5] = {1, 2, 3, 4, 5}; + int32_t valArray[6] = {1, 2, 4, 8, 16, 32}; + for (int32_t exp : expArray) { + for (int32_t val : valArray) { + ASSERT_FP_EQ(T(val << exp), func(T(val), exp)); + ASSERT_FP_EQ(T(-1 * (val << exp)), func(T(-val), exp)); + } + } + } + + void testOverflow(LdExpFunc func) { + NormalFloat x(FPBits::maxExponent - 10, NormalFloat::one + 0xF00BA, 0); + for (int32_t exp = 10; exp < 100; ++exp) { + ASSERT_FP_EQ(inf, func(T(x), exp)); + ASSERT_FP_EQ(negInf, func(-T(x), exp)); + } + } + + void testUnderflowToZeroOnNormal(LdExpFunc func) { + // In this test, we pass a normal nubmer to func and expect zero + // to be returned due to underflow. + int32_t baseExponent = FPBits::exponentBias + mantissaWidth; + int32_t expArray[] = {baseExponent + 5, baseExponent + 4, baseExponent + 3, + baseExponent + 2, baseExponent + 1}; + T x = NormalFloat(0, mantissa, 0); + for (int32_t exp : expArray) { + ASSERT_FP_EQ(func(x, -exp), x > 0 ? zero : negZero); + } + } + + void testUnderflowToZeroOnSubnormal(LdExpFunc func) { + // In this test, we pass a normal nubmer to func and expect zero + // to be returned due to underflow. + int32_t baseExponent = FPBits::exponentBias + mantissaWidth; + int32_t expArray[] = {baseExponent + 5, baseExponent + 4, baseExponent + 3, + baseExponent + 2, baseExponent + 1}; + T x = NormalFloat(-FPBits::exponentBias, mantissa, 0); + for (int32_t exp : expArray) { + ASSERT_FP_EQ(func(x, -exp), x > 0 ? zero : negZero); + } + } + + void testNormalOperation(LdExpFunc func) { + T valArray[] = { + // Normal numbers + NormalFloat(100, mantissa, 0), NormalFloat(-100, mantissa, 0), + NormalFloat(100, mantissa, 1), NormalFloat(-100, mantissa, 1), + // Subnormal numbers + NormalFloat(-FPBits::exponentBias, mantissa, 0), + NormalFloat(-FPBits::exponentBias, mantissa, 1)}; + for (int32_t exp = 0; exp <= static_cast<int32_t>(mantissaWidth); ++exp) { + for (T x : valArray) { + // We compare the result of ldexp with the result + // of the native multiplication/division instruction. + ASSERT_FP_EQ(func(x, exp), x * (UIntType(1) << exp)); + ASSERT_FP_EQ(func(x, -exp), x / (UIntType(1) << exp)); + } + } + + // Normal which trigger mantissa overflow. + T x = NormalFloat(-FPBits::exponentBias + 1, 2 * NormalFloat::one - 1, 0); + ASSERT_FP_EQ(func(x, -1), x / 2); + ASSERT_FP_EQ(func(-x, -1), -x / 2); + } +}; + +#define LIST_LDEXP_TESTS(T, func) \ + using LdExpTest = LdExpTestTemplate<T>; \ + TEST_F(LdExpTest, SpecialNumbers) { testSpecialNumbers(&func); } \ + TEST_F(LdExpTest, PowersOfTwo) { testPowersOfTwo(&func); } \ + TEST_F(LdExpTest, OverFlow) { testOverflow(&func); } \ + TEST_F(LdExpTest, UnderflowToZeroOnNormal) { \ + testUnderflowToZeroOnNormal(&func); \ + } \ + TEST_F(LdExpTest, UnderflowToZeroOnSubnormal) { \ + testUnderflowToZeroOnSubnormal(&func); \ + } \ + TEST_F(LdExpTest, NormalOperation) { testNormalOperation(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H diff --git a/libc/test/src/math/ldexp_test.cpp b/libc/test/src/math/ldexp_test.cpp new file mode 100644 index 000000000000..0f5974c018f7 --- /dev/null +++ b/libc/test/src/math/ldexp_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for ldexp -----------------------------------------------===// +// +// 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 "LdExpTest.h" + +#include "include/math.h" +#include "src/math/ldexp.h" +#include "utils/CPP/Functional.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/FPUtil/ManipulationFunctions.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/UnitTest/Test.h" + +#include <limits.h> + +LIST_LDEXP_TESTS(double, __llvm_libc::ldexp) diff --git a/libc/test/src/math/ldexpf_test.cpp b/libc/test/src/math/ldexpf_test.cpp new file mode 100644 index 000000000000..d9a44b3f4125 --- /dev/null +++ b/libc/test/src/math/ldexpf_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for ldexpf ----------------------------------------------===// +// +// 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 "LdExpTest.h" + +#include "include/math.h" +#include "src/math/ldexpf.h" +#include "utils/CPP/Functional.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/FPUtil/ManipulationFunctions.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/UnitTest/Test.h" + +#include <limits.h> + +LIST_LDEXP_TESTS(float, __llvm_libc::ldexpf) diff --git a/libc/test/src/math/ldexpl_test.cpp b/libc/test/src/math/ldexpl_test.cpp new file mode 100644 index 000000000000..69444b6edbaf --- /dev/null +++ b/libc/test/src/math/ldexpl_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for ldexpl ----------------------------------------------===// +// +// 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 "LdExpTest.h" + +#include "include/math.h" +#include "src/math/ldexpl.h" +#include "utils/CPP/Functional.h" +#include "utils/FPUtil/FPBits.h" +#include "utils/FPUtil/ManipulationFunctions.h" +#include "utils/FPUtil/TestHelpers.h" +#include "utils/UnitTest/Test.h" + +#include <limits.h> + +LIST_LDEXP_TESTS(long double, __llvm_libc::ldexpl) |