forked from OSchip/llvm-project
[libc] Consolidate floating point utils into a single utils library.
A new utils library named 'fputil' is added. This library is used in math tests and the MPFR wrapper. The math implementations will be modified to use this library in a later round. Reviewers: phosek Differential Revision: https://reviews.llvm.org/D79724
This commit is contained in:
parent
e36223c85c
commit
32a22a423c
|
@ -23,12 +23,6 @@ function(add_math_unittest name)
|
||||||
endif()
|
endif()
|
||||||
endfunction(add_math_unittest)
|
endfunction(add_math_unittest)
|
||||||
|
|
||||||
add_header_library(
|
|
||||||
float_utils
|
|
||||||
HDRS
|
|
||||||
float.h
|
|
||||||
)
|
|
||||||
|
|
||||||
add_math_unittest(
|
add_math_unittest(
|
||||||
cosf_test
|
cosf_test
|
||||||
NEED_MPFR
|
NEED_MPFR
|
||||||
|
@ -39,9 +33,10 @@ add_math_unittest(
|
||||||
HDRS
|
HDRS
|
||||||
sdcomp26094.h
|
sdcomp26094.h
|
||||||
DEPENDS
|
DEPENDS
|
||||||
.float_utils
|
libc.include.errno
|
||||||
libc.src.math.cosf
|
libc.src.math.cosf
|
||||||
libc.utils.CPP.standalone_cpp
|
libc.utils.CPP.standalone_cpp
|
||||||
|
libc.utils.FPUtil.fputil
|
||||||
)
|
)
|
||||||
|
|
||||||
add_math_unittest(
|
add_math_unittest(
|
||||||
|
@ -54,9 +49,10 @@ add_math_unittest(
|
||||||
HDRS
|
HDRS
|
||||||
sdcomp26094.h
|
sdcomp26094.h
|
||||||
DEPENDS
|
DEPENDS
|
||||||
.float_utils
|
libc.include.errno
|
||||||
libc.src.math.sinf
|
libc.src.math.sinf
|
||||||
libc.utils.CPP.standalone_cpp
|
libc.utils.CPP.standalone_cpp
|
||||||
|
libc.utils.FPUtil.fputil
|
||||||
)
|
)
|
||||||
|
|
||||||
add_math_unittest(
|
add_math_unittest(
|
||||||
|
@ -69,7 +65,8 @@ add_math_unittest(
|
||||||
HDRS
|
HDRS
|
||||||
sdcomp26094.h
|
sdcomp26094.h
|
||||||
DEPENDS
|
DEPENDS
|
||||||
.float_utils
|
libc.include.errno
|
||||||
libc.src.math.sincosf
|
libc.src.math.sincosf
|
||||||
libc.utils.CPP.standalone_cpp
|
libc.utils.CPP.standalone_cpp
|
||||||
|
libc.utils.FPUtil.fputil
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,22 +6,27 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "include/errno.h"
|
||||||
#include "include/math.h"
|
#include "include/math.h"
|
||||||
#include "src/errno/llvmlibc_errno.h"
|
#include "src/errno/llvmlibc_errno.h"
|
||||||
#include "src/math/cosf.h"
|
#include "src/math/cosf.h"
|
||||||
#include "src/math/math_utils.h"
|
|
||||||
#include "test/src/math/float.h"
|
|
||||||
#include "test/src/math/sdcomp26094.h"
|
#include "test/src/math/sdcomp26094.h"
|
||||||
#include "utils/CPP/Array.h"
|
#include "utils/CPP/Array.h"
|
||||||
|
#include "utils/FPUtil/BitPatterns.h"
|
||||||
|
#include "utils/FPUtil/FloatOperations.h"
|
||||||
|
#include "utils/FPUtil/FloatProperties.h"
|
||||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
#include "utils/UnitTest/Test.h"
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
using __llvm_libc::as_float;
|
using __llvm_libc::fputil::isNegativeQuietNaN;
|
||||||
using __llvm_libc::as_uint32_bits;
|
using __llvm_libc::fputil::isQuietNaN;
|
||||||
|
using __llvm_libc::fputil::valueAsBits;
|
||||||
|
using __llvm_libc::fputil::valueFromBits;
|
||||||
|
|
||||||
|
using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
|
||||||
|
|
||||||
using __llvm_libc::testing::FloatBits;
|
|
||||||
using __llvm_libc::testing::sdcomp26094Values;
|
using __llvm_libc::testing::sdcomp26094Values;
|
||||||
|
|
||||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
@ -34,38 +39,37 @@ static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
|
||||||
TEST(CosfTest, SpecialNumbers) {
|
TEST(CosfTest, SpecialNumbers) {
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::QNan)))));
|
isQuietNaN(__llvm_libc::cosf(valueFromBits(BitPatterns::aQuietNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegQNan)))));
|
__llvm_libc::cosf(valueFromBits(BitPatterns::aNegativeQuietNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(isQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::SNan)))));
|
__llvm_libc::cosf(valueFromBits(BitPatterns::aSignallingNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegSNan)))));
|
__llvm_libc::cosf(valueFromBits(BitPatterns::aNegativeSignallingNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_EQ(FloatBits::One,
|
EXPECT_EQ(BitPatterns::one,
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::Zero))));
|
valueAsBits(__llvm_libc::cosf(valueFromBits(BitPatterns::zero))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_EQ(FloatBits::One,
|
EXPECT_EQ(BitPatterns::one, valueAsBits(__llvm_libc::cosf(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegZero))));
|
valueFromBits(BitPatterns::negZero))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(isQuietNaN(__llvm_libc::cosf(valueFromBits(BitPatterns::inf))));
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::Inf)))));
|
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegInf)))));
|
__llvm_libc::cosf(valueFromBits(BitPatterns::negInf))));
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +77,7 @@ TEST(CosfTest, InFloatRange) {
|
||||||
constexpr uint32_t count = 1000000;
|
constexpr uint32_t count = 1000000;
|
||||||
constexpr uint32_t step = UINT32_MAX / count;
|
constexpr uint32_t step = UINT32_MAX / count;
|
||||||
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
if (isnan(x) || isinf(x))
|
if (isnan(x) || isinf(x))
|
||||||
continue;
|
continue;
|
||||||
ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
|
ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
|
||||||
|
@ -82,22 +86,22 @@ TEST(CosfTest, InFloatRange) {
|
||||||
|
|
||||||
// For small values, cos(x) is 1.
|
// For small values, cos(x) is 1.
|
||||||
TEST(CosfTest, SmallValues) {
|
TEST(CosfTest, SmallValues) {
|
||||||
float x = as_float(0x17800000);
|
float x = valueFromBits(0x17800000U);
|
||||||
float result = __llvm_libc::cosf(x);
|
float result = __llvm_libc::cosf(x);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(result));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(result));
|
||||||
|
|
||||||
x = as_float(0x0040000);
|
x = valueFromBits(0x0040000U);
|
||||||
result = __llvm_libc::cosf(x);
|
result = __llvm_libc::cosf(x);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(result));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDCOMP-26094: check cosf in the cases for which the range reducer
|
// SDCOMP-26094: check cosf in the cases for which the range reducer
|
||||||
// returns values furthest beyond its nominal upper bound of pi/4.
|
// returns values furthest beyond its nominal upper bound of pi/4.
|
||||||
TEST(CosfTest, SDCOMP_26094) {
|
TEST(CosfTest, SDCOMP_26094) {
|
||||||
for (uint32_t v : sdcomp26094Values) {
|
for (uint32_t v : sdcomp26094Values) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
|
ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
//===-- Single precision floating point test utils --------------*- 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_FLOAT_H
|
|
||||||
#define LLVM_LIBC_TEST_SRC_MATH_FLOAT_H
|
|
||||||
|
|
||||||
#include "src/math/math_utils.h"
|
|
||||||
|
|
||||||
namespace __llvm_libc {
|
|
||||||
namespace testing {
|
|
||||||
|
|
||||||
struct FloatBits {
|
|
||||||
// The various NaN bit patterns here are just one of the many possible
|
|
||||||
// patterns. The functions isQNan and isNegQNan can help understand why.
|
|
||||||
|
|
||||||
static const uint32_t QNan = 0x7fc00000;
|
|
||||||
static const uint32_t NegQNan = 0xffc00000;
|
|
||||||
|
|
||||||
static const uint32_t SNan = 0x7f800001;
|
|
||||||
static const uint32_t NegSNan = 0xff800001;
|
|
||||||
|
|
||||||
static bool isQNan(float f) {
|
|
||||||
uint32_t bits = as_uint32_bits(f);
|
|
||||||
return ((0x7fc00000 & bits) != 0) && ((0x80000000 & bits) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isNegQNan(float f) {
|
|
||||||
uint32_t bits = as_uint32_bits(f);
|
|
||||||
return 0xffc00000 & bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr uint32_t Zero = 0x0;
|
|
||||||
static constexpr uint32_t NegZero = 0x80000000;
|
|
||||||
|
|
||||||
static constexpr uint32_t Inf = 0x7f800000;
|
|
||||||
static constexpr uint32_t NegInf = 0xff800000;
|
|
||||||
|
|
||||||
static constexpr uint32_t One = 0x3f800000;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace testing
|
|
||||||
} // namespace __llvm_libc
|
|
||||||
|
|
||||||
#endif // LLVM_LIBC_TEST_SRC_MATH_FLOAT_H
|
|
|
@ -10,14 +10,17 @@
|
||||||
#define LLVM_LIBC_TEST_SRC_MATH_SDCOMP26094_H
|
#define LLVM_LIBC_TEST_SRC_MATH_SDCOMP26094_H
|
||||||
|
|
||||||
#include "utils/CPP/Array.h"
|
#include "utils/CPP/Array.h"
|
||||||
|
#include "utils/FPUtil/BitPatterns.h"
|
||||||
|
|
||||||
namespace __llvm_libc {
|
namespace __llvm_libc {
|
||||||
namespace testing {
|
namespace testing {
|
||||||
|
|
||||||
static constexpr __llvm_libc::cpp::Array<uint32_t, 10> sdcomp26094Values{
|
static constexpr __llvm_libc::cpp::Array<fputil::BitPatterns<float>::BitsType,
|
||||||
0x46427f1b, 0x4647e568, 0x46428bac, 0x4647f1f9, 0x4647fe8a,
|
10>
|
||||||
0x45d8d7f1, 0x45d371a4, 0x45ce0b57, 0x45d35882, 0x45cdf235,
|
sdcomp26094Values{
|
||||||
};
|
0x46427f1b, 0x4647e568, 0x46428bac, 0x4647f1f9, 0x4647fe8a,
|
||||||
|
0x45d8d7f1, 0x45d371a4, 0x45ce0b57, 0x45d35882, 0x45cdf235,
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
} // namespace __llvm_libc
|
} // namespace __llvm_libc
|
||||||
|
|
|
@ -6,25 +6,31 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "include/errno.h"
|
||||||
#include "include/math.h"
|
#include "include/math.h"
|
||||||
#include "src/errno/llvmlibc_errno.h"
|
#include "src/errno/llvmlibc_errno.h"
|
||||||
#include "src/math/math_utils.h"
|
|
||||||
#include "src/math/sincosf.h"
|
#include "src/math/sincosf.h"
|
||||||
#include "test/src/math/float.h"
|
|
||||||
#include "test/src/math/sdcomp26094.h"
|
#include "test/src/math/sdcomp26094.h"
|
||||||
#include "utils/CPP/Array.h"
|
#include "utils/CPP/Array.h"
|
||||||
|
#include "utils/FPUtil/BitPatterns.h"
|
||||||
|
#include "utils/FPUtil/FloatOperations.h"
|
||||||
|
#include "utils/FPUtil/FloatProperties.h"
|
||||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
#include "utils/UnitTest/Test.h"
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
using __llvm_libc::as_float;
|
using __llvm_libc::fputil::isNegativeQuietNaN;
|
||||||
using __llvm_libc::as_uint32_bits;
|
using __llvm_libc::fputil::isQuietNaN;
|
||||||
|
using __llvm_libc::fputil::valueAsBits;
|
||||||
|
using __llvm_libc::fputil::valueFromBits;
|
||||||
|
|
||||||
|
using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
|
||||||
|
|
||||||
using __llvm_libc::testing::FloatBits;
|
|
||||||
using __llvm_libc::testing::sdcomp26094Values;
|
using __llvm_libc::testing::sdcomp26094Values;
|
||||||
|
|
||||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
|
||||||
// 12 additional bits of precision over the base precision of a |float|
|
// 12 additional bits of precision over the base precision of a |float|
|
||||||
// value.
|
// value.
|
||||||
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
|
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
|
||||||
|
@ -34,46 +40,48 @@ TEST(SinCosfTest, SpecialNumbers) {
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
float sin, cos;
|
float sin, cos;
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::QNan), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::aQuietNaN), &sin, &cos);
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
|
EXPECT_TRUE(isQuietNaN(cos));
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::NegQNan), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::aNegativeQuietNaN), &sin,
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(cos)));
|
&cos);
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isNegativeQuietNaN(cos));
|
||||||
|
EXPECT_TRUE(isNegativeQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::SNan), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::aSignallingNaN), &sin, &cos);
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
|
EXPECT_TRUE(isQuietNaN(cos));
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::NegSNan), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::aNegativeSignallingNaN), &sin,
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(cos)));
|
&cos);
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isNegativeQuietNaN(cos));
|
||||||
|
EXPECT_TRUE(isNegativeQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::Zero), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::zero), &sin, &cos);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(cos));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(cos));
|
||||||
EXPECT_EQ(FloatBits::Zero, as_uint32_bits(sin));
|
EXPECT_EQ(BitPatterns::zero, valueAsBits(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::NegZero), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::negZero), &sin, &cos);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(cos));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(cos));
|
||||||
EXPECT_EQ(FloatBits::NegZero, as_uint32_bits(sin));
|
EXPECT_EQ(BitPatterns::negZero, valueAsBits(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::Inf), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::inf), &sin, &cos);
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
|
EXPECT_TRUE(isQuietNaN(cos));
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
__llvm_libc::sincosf(as_float(FloatBits::NegInf), &sin, &cos);
|
__llvm_libc::sincosf(valueFromBits(BitPatterns::negInf), &sin, &cos);
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
|
EXPECT_TRUE(isQuietNaN(cos));
|
||||||
EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
|
EXPECT_TRUE(isQuietNaN(sin));
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +89,7 @@ TEST(SinCosfTest, InFloatRange) {
|
||||||
constexpr uint32_t count = 1000000;
|
constexpr uint32_t count = 1000000;
|
||||||
constexpr uint32_t step = UINT32_MAX / count;
|
constexpr uint32_t step = UINT32_MAX / count;
|
||||||
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
if (isnan(x) || isinf(x))
|
if (isnan(x) || isinf(x))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -95,28 +103,28 @@ TEST(SinCosfTest, InFloatRange) {
|
||||||
// For small values, cos(x) is 1 and sin(x) is x.
|
// For small values, cos(x) is 1 and sin(x) is x.
|
||||||
TEST(SinCosfTest, SmallValues) {
|
TEST(SinCosfTest, SmallValues) {
|
||||||
uint32_t bits = 0x17800000;
|
uint32_t bits = 0x17800000;
|
||||||
float x = as_float(bits);
|
float x = valueFromBits(bits);
|
||||||
float result_cos, result_sin;
|
float result_cos, result_sin;
|
||||||
__llvm_libc::sincosf(x, &result_sin, &result_cos);
|
__llvm_libc::sincosf(x, &result_sin, &result_cos);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(result_cos));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
|
||||||
EXPECT_EQ(bits, as_uint32_bits(result_sin));
|
EXPECT_EQ(bits, valueAsBits(result_sin));
|
||||||
|
|
||||||
bits = 0x00400000;
|
bits = 0x00400000;
|
||||||
x = as_float(bits);
|
x = valueFromBits(bits);
|
||||||
__llvm_libc::sincosf(x, &result_sin, &result_cos);
|
__llvm_libc::sincosf(x, &result_sin, &result_cos);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
|
||||||
EXPECT_EQ(FloatBits::One, as_uint32_bits(result_cos));
|
EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
|
||||||
EXPECT_EQ(bits, as_uint32_bits(result_sin));
|
EXPECT_EQ(bits, valueAsBits(result_sin));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDCOMP-26094: check sinf in the cases for which the range reducer
|
// SDCOMP-26094: check sinf in the cases for which the range reducer
|
||||||
// returns values furthest beyond its nominal upper bound of pi/4.
|
// returns values furthest beyond its nominal upper bound of pi/4.
|
||||||
TEST(SinCosfTest, SDCOMP_26094) {
|
TEST(SinCosfTest, SDCOMP_26094) {
|
||||||
for (uint32_t v : sdcomp26094Values) {
|
for (uint32_t v : sdcomp26094Values) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
float sin, cos;
|
float sin, cos;
|
||||||
__llvm_libc::sincosf(x, &sin, &cos);
|
__llvm_libc::sincosf(x, &sin, &cos);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, cos, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, cos, tolerance);
|
||||||
|
|
|
@ -6,22 +6,27 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "include/errno.h"
|
||||||
#include "include/math.h"
|
#include "include/math.h"
|
||||||
#include "src/errno/llvmlibc_errno.h"
|
#include "src/errno/llvmlibc_errno.h"
|
||||||
#include "src/math/math_utils.h"
|
|
||||||
#include "src/math/sinf.h"
|
#include "src/math/sinf.h"
|
||||||
#include "test/src/math/float.h"
|
|
||||||
#include "test/src/math/sdcomp26094.h"
|
#include "test/src/math/sdcomp26094.h"
|
||||||
#include "utils/CPP/Array.h"
|
#include "utils/CPP/Array.h"
|
||||||
|
#include "utils/FPUtil/BitPatterns.h"
|
||||||
|
#include "utils/FPUtil/FloatOperations.h"
|
||||||
|
#include "utils/FPUtil/FloatProperties.h"
|
||||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
#include "utils/UnitTest/Test.h"
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
using __llvm_libc::as_float;
|
using __llvm_libc::fputil::isNegativeQuietNaN;
|
||||||
using __llvm_libc::as_uint32_bits;
|
using __llvm_libc::fputil::isQuietNaN;
|
||||||
|
using __llvm_libc::fputil::valueAsBits;
|
||||||
|
using __llvm_libc::fputil::valueFromBits;
|
||||||
|
|
||||||
|
using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
|
||||||
|
|
||||||
using __llvm_libc::testing::FloatBits;
|
|
||||||
using __llvm_libc::testing::sdcomp26094Values;
|
using __llvm_libc::testing::sdcomp26094Values;
|
||||||
|
|
||||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
@ -34,38 +39,37 @@ static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
|
||||||
TEST(SinfTest, SpecialNumbers) {
|
TEST(SinfTest, SpecialNumbers) {
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::QNan)))));
|
isQuietNaN(__llvm_libc::sinf(valueFromBits(BitPatterns::aQuietNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegQNan)))));
|
__llvm_libc::sinf(valueFromBits(BitPatterns::aNegativeQuietNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(isQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::SNan)))));
|
__llvm_libc::sinf(valueFromBits(BitPatterns::aSignallingNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegSNan)))));
|
__llvm_libc::sinf(valueFromBits(BitPatterns::aNegativeSignallingNaN))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_EQ(FloatBits::Zero,
|
EXPECT_EQ(BitPatterns::zero,
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::Zero))));
|
valueAsBits(__llvm_libc::sinf(valueFromBits(BitPatterns::zero))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
EXPECT_EQ(FloatBits::NegZero,
|
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::sinf(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegZero))));
|
valueFromBits(BitPatterns::negZero))));
|
||||||
EXPECT_EQ(llvmlibc_errno, 0);
|
EXPECT_EQ(llvmlibc_errno, 0);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
EXPECT_TRUE(FloatBits::isQNan(
|
EXPECT_TRUE(isQuietNaN(__llvm_libc::sinf(valueFromBits(BitPatterns::inf))));
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::Inf)))));
|
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
|
|
||||||
llvmlibc_errno = 0;
|
llvmlibc_errno = 0;
|
||||||
EXPECT_TRUE(FloatBits::isNegQNan(
|
EXPECT_TRUE(isNegativeQuietNaN(
|
||||||
as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegInf)))));
|
__llvm_libc::sinf(valueFromBits(BitPatterns::negInf))));
|
||||||
EXPECT_EQ(llvmlibc_errno, EDOM);
|
EXPECT_EQ(llvmlibc_errno, EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +77,7 @@ TEST(SinfTest, InFloatRange) {
|
||||||
constexpr uint32_t count = 1000000;
|
constexpr uint32_t count = 1000000;
|
||||||
constexpr uint32_t step = UINT32_MAX / count;
|
constexpr uint32_t step = UINT32_MAX / count;
|
||||||
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
if (isnan(x) || isinf(x))
|
if (isnan(x) || isinf(x))
|
||||||
continue;
|
continue;
|
||||||
ASSERT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
ASSERT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
||||||
|
@ -81,30 +85,30 @@ TEST(SinfTest, InFloatRange) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SinfTest, SpecificBitPatterns) {
|
TEST(SinfTest, SpecificBitPatterns) {
|
||||||
float x = as_float(0xc70d39a1);
|
float x = valueFromBits(0xc70d39a1);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For small values, sin(x) is x.
|
// For small values, sin(x) is x.
|
||||||
TEST(SinfTest, SmallValues) {
|
TEST(SinfTest, SmallValues) {
|
||||||
uint32_t bits = 0x17800000;
|
uint32_t bits = 0x17800000;
|
||||||
float x = as_float(bits);
|
float x = valueFromBits(bits);
|
||||||
float result = __llvm_libc::sinf(x);
|
float result = __llvm_libc::sinf(x);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
|
||||||
EXPECT_EQ(bits, as_uint32_bits(result));
|
EXPECT_EQ(bits, valueAsBits(result));
|
||||||
|
|
||||||
bits = 0x00400000;
|
bits = 0x00400000;
|
||||||
x = as_float(bits);
|
x = valueFromBits(bits);
|
||||||
result = __llvm_libc::sinf(x);
|
result = __llvm_libc::sinf(x);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
|
||||||
EXPECT_EQ(bits, as_uint32_bits(result));
|
EXPECT_EQ(bits, valueAsBits(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDCOMP-26094: check sinf in the cases for which the range reducer
|
// SDCOMP-26094: check sinf in the cases for which the range reducer
|
||||||
// returns values furthest beyond its nominal upper bound of pi/4.
|
// returns values furthest beyond its nominal upper bound of pi/4.
|
||||||
TEST(SinfTest, SDCOMP_26094) {
|
TEST(SinfTest, SDCOMP_26094) {
|
||||||
for (uint32_t v : sdcomp26094Values) {
|
for (uint32_t v : sdcomp26094Values) {
|
||||||
float x = as_float(v);
|
float x = valueFromBits(v);
|
||||||
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
add_subdirectory(CPP)
|
add_subdirectory(CPP)
|
||||||
|
add_subdirectory(FPUtil)
|
||||||
add_subdirectory(HdrGen)
|
add_subdirectory(HdrGen)
|
||||||
add_subdirectory(MPFRWrapper)
|
add_subdirectory(MPFRWrapper)
|
||||||
add_subdirectory(testutils)
|
add_subdirectory(testutils)
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
//===-- Bit patterns of common floating point numbers -----------*- 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_BIT_PATTERNS_H
|
||||||
|
#define LLVM_LIBC_UTILS_FPUTIL_BIT_PATTERNS_H
|
||||||
|
|
||||||
|
#include "FloatProperties.h"
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
namespace fputil {
|
||||||
|
|
||||||
|
template <typename T> struct BitPatterns {};
|
||||||
|
|
||||||
|
template <> struct BitPatterns<float> {
|
||||||
|
using BitsType = FloatProperties<float>::BitsType;
|
||||||
|
|
||||||
|
static constexpr BitsType inf = 0x7f800000U;
|
||||||
|
static constexpr BitsType negInf = 0xff800000U;
|
||||||
|
|
||||||
|
static constexpr BitsType zero = 0x0;
|
||||||
|
static constexpr BitsType negZero = 0x80000000U;
|
||||||
|
|
||||||
|
static constexpr BitsType one = 0x3f800000U;
|
||||||
|
|
||||||
|
// Examples of quiet NAN.
|
||||||
|
static constexpr BitsType aQuietNaN = 0x7fc00000U;
|
||||||
|
static constexpr BitsType aNegativeQuietNaN = 0xffc00000U;
|
||||||
|
|
||||||
|
// Examples of signalling NAN.
|
||||||
|
static constexpr BitsType aSignallingNaN = 0x7f800001U;
|
||||||
|
static constexpr BitsType aNegativeSignallingNaN = 0xff800001U;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct BitPatterns<double> {
|
||||||
|
using BitsType = FloatProperties<double>::BitsType;
|
||||||
|
|
||||||
|
static constexpr BitsType inf = 0x7ff0000000000000ULL;
|
||||||
|
static constexpr BitsType negInf = 0xfff0000000000000ULL;
|
||||||
|
|
||||||
|
static constexpr BitsType zero = 0x0ULL;
|
||||||
|
static constexpr BitsType negZero = 0x8000000000000000ULL;
|
||||||
|
|
||||||
|
static constexpr BitsType one = 0x3FF0000000000000ULL;
|
||||||
|
|
||||||
|
// Examples of quiet NAN.
|
||||||
|
static constexpr BitsType aQuietNaN = 0x7ff8000000000000ULL;
|
||||||
|
static constexpr BitsType aNegativeQuietNaN = 0xfff8000000000000ULL;
|
||||||
|
|
||||||
|
// Examples of signalling NAN.
|
||||||
|
static constexpr BitsType aSignallingNaN = 0x7ff0000000000001ULL;
|
||||||
|
static constexpr BitsType aNegativeSignallingNaN = 0xfff0000000000001ULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fputil
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_UTILS_FPUTIL_BIT_PATTERNS_H
|
|
@ -0,0 +1,9 @@
|
||||||
|
add_header_library(
|
||||||
|
fputil
|
||||||
|
HDRS
|
||||||
|
BitPatterns.h
|
||||||
|
FloatOperations.h
|
||||||
|
FloatProperties.h
|
||||||
|
DEPS
|
||||||
|
libc.utils.CPP.standalone_cpp
|
||||||
|
)
|
|
@ -0,0 +1,102 @@
|
||||||
|
//===-- Common operations on floating point numbers -------------*- 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_FLOAT_OPERATIONS_H
|
||||||
|
#define LLVM_LIBC_UTILS_FPUTIL_FLOAT_OPERATIONS_H
|
||||||
|
|
||||||
|
#include "BitPatterns.h"
|
||||||
|
#include "FloatProperties.h"
|
||||||
|
|
||||||
|
#include "utils/CPP/TypeTraits.h"
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
namespace fputil {
|
||||||
|
|
||||||
|
// Return the bits of a float value.
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline typename FloatProperties<T>::BitsType valueAsBits(T x) {
|
||||||
|
using BitsType = typename FloatProperties<T>::BitsType;
|
||||||
|
return *reinterpret_cast<BitsType *>(&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the float value from bits.
|
||||||
|
template <typename BitsType,
|
||||||
|
cpp::EnableIfType<
|
||||||
|
cpp::IsFloatingPointType<FloatTypeT<BitsType>>::Value, int> = 0>
|
||||||
|
static inline FloatTypeT<BitsType> valueFromBits(BitsType bits) {
|
||||||
|
return *reinterpret_cast<FloatTypeT<BitsType> *>(&bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the bits of abs(x).
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline typename FloatProperties<T>::BitsType absBits(T x) {
|
||||||
|
return valueAsBits(x) & (~FloatProperties<T>::signMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the zero adjusted exponent value of x.
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
int getExponent(T x) {
|
||||||
|
using Properties = FloatProperties<T>;
|
||||||
|
using BitsType = typename Properties::BitsType;
|
||||||
|
BitsType bits = absBits(x);
|
||||||
|
int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa.
|
||||||
|
e -= Properties::exponentOffset; // Zero adjust.
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if x is infinity (positive or negative.)
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline bool isInf(T x) {
|
||||||
|
using Properties = FloatProperties<T>;
|
||||||
|
using BitsType = typename FloatProperties<T>::BitsType;
|
||||||
|
BitsType bits = valueAsBits(x);
|
||||||
|
return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
|
||||||
|
((bits & Properties::mantissaMask) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if x is a NAN (quiet or signalling.)
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline bool isNaN(T x) {
|
||||||
|
using Properties = FloatProperties<T>;
|
||||||
|
using BitsType = typename FloatProperties<T>::BitsType;
|
||||||
|
BitsType bits = valueAsBits(x);
|
||||||
|
return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
|
||||||
|
((bits & Properties::mantissaMask) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if x is a quiet NAN.
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline bool isQuietNaN(T x) {
|
||||||
|
using Properties = FloatProperties<T>;
|
||||||
|
using BitsType = typename FloatProperties<T>::BitsType;
|
||||||
|
BitsType bits = valueAsBits(x);
|
||||||
|
return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
|
||||||
|
((bits & Properties::quietNaNMask) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if x is a quiet NAN with sign bit set.
|
||||||
|
template <typename T,
|
||||||
|
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||||
|
static inline bool isNegativeQuietNaN(T x) {
|
||||||
|
using Properties = FloatProperties<T>;
|
||||||
|
using BitsType = typename FloatProperties<T>::BitsType;
|
||||||
|
BitsType bits = valueAsBits(x);
|
||||||
|
return ((bits & BitPatterns<T>::negInf) == BitPatterns<T>::negInf) &&
|
||||||
|
((bits & Properties::quietNaNMask) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fputil
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_UTILS_FPUTIL_FLOAT_OPERATIONS_H
|
|
@ -0,0 +1,72 @@
|
||||||
|
//===-- Properties of floating point numbers --------------------*- 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_FLOAT_PROPERTIES_H
|
||||||
|
#define LLVM_LIBC_UTILS_FPUTIL_FLOAT_PROPERTIES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
namespace fputil {
|
||||||
|
|
||||||
|
template <typename T> struct FloatProperties {};
|
||||||
|
|
||||||
|
template <> struct FloatProperties<float> {
|
||||||
|
typedef uint32_t BitsType;
|
||||||
|
static_assert(sizeof(BitsType) == sizeof(float),
|
||||||
|
"Unexpected size of 'float' type.");
|
||||||
|
|
||||||
|
static constexpr uint32_t mantissaWidth = 23;
|
||||||
|
static constexpr BitsType mantissaMask = 0x007fffffU;
|
||||||
|
static constexpr BitsType signMask = 0x80000000U;
|
||||||
|
static constexpr uint32_t exponentOffset = 127;
|
||||||
|
|
||||||
|
// If a number x is a NAN, then it is a quiet NAN if:
|
||||||
|
// QuietNaNMask & bits(x) != 0
|
||||||
|
// Else, it is a signalling NAN.
|
||||||
|
static constexpr BitsType quietNaNMask = 0x00400000U;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct FloatProperties<double> {
|
||||||
|
typedef uint64_t BitsType;
|
||||||
|
static_assert(sizeof(BitsType) == sizeof(double),
|
||||||
|
"Unexpected size of 'double' type.");
|
||||||
|
|
||||||
|
static constexpr uint32_t mantissaWidth = 52;
|
||||||
|
static constexpr BitsType mantissaMask = 0x000fffffffffffffU;
|
||||||
|
static constexpr BitsType signMask = 0x8000000000000000ULL;
|
||||||
|
static constexpr uint32_t exponentOffset = 1023;
|
||||||
|
|
||||||
|
// If a number x is a NAN, then it is a quiet NAN if:
|
||||||
|
// QuietNaNMask & bits(x) != 0
|
||||||
|
// Else, it is a signalling NAN.
|
||||||
|
static constexpr BitsType quietNaNMask = 0x0008000000000000ULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define the float type corresponding to the BitsType.
|
||||||
|
template <typename BitsType> struct FloatType;
|
||||||
|
|
||||||
|
template <> struct FloatType<uint32_t> {
|
||||||
|
static_assert(sizeof(uint32_t) == sizeof(float),
|
||||||
|
"Unexpected size of 'float' type.");
|
||||||
|
typedef float Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct FloatType<uint64_t> {
|
||||||
|
static_assert(sizeof(uint64_t) == sizeof(double),
|
||||||
|
"Unexpected size of 'double' type.");
|
||||||
|
typedef double Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename BitsType>
|
||||||
|
using FloatTypeT = typename FloatType<BitsType>::Type;
|
||||||
|
|
||||||
|
} // namespace fputil
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_UTILS_FPUTIL_FLOAT_PROPERTIES_H
|
|
@ -12,7 +12,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
|
||||||
MPFRUtils.cpp
|
MPFRUtils.cpp
|
||||||
MPFRUtils.h
|
MPFRUtils.h
|
||||||
)
|
)
|
||||||
add_dependencies(libcMPFRWrapper libc.utils.CPP.standalone_cpp LibcUnitTest LLVMSupport)
|
add_dependencies(libcMPFRWrapper libc.utils.CPP.standalone_cpp libc.utils.FPUtil.fputil LibcUnitTest LLVMSupport)
|
||||||
target_link_libraries(libcMPFRWrapper -lmpfr -lgmp LibcUnitTest LLVMSupport)
|
target_link_libraries(libcMPFRWrapper -lmpfr -lgmp LibcUnitTest LLVMSupport)
|
||||||
else()
|
else()
|
||||||
message(WARNING "Math tests using MPFR will be skipped.")
|
message(WARNING "Math tests using MPFR will be skipped.")
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "MPFRUtils.h"
|
#include "MPFRUtils.h"
|
||||||
|
|
||||||
|
#include "utils/FPUtil/FloatOperations.h"
|
||||||
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
|
||||||
|
@ -19,44 +21,6 @@ namespace __llvm_libc {
|
||||||
namespace testing {
|
namespace testing {
|
||||||
namespace mpfr {
|
namespace mpfr {
|
||||||
|
|
||||||
template <typename T> struct FloatProperties {};
|
|
||||||
|
|
||||||
template <> struct FloatProperties<float> {
|
|
||||||
typedef uint32_t BitsType;
|
|
||||||
static_assert(sizeof(BitsType) == sizeof(float),
|
|
||||||
"Unexpected size of 'float' type.");
|
|
||||||
|
|
||||||
static constexpr uint32_t mantissaWidth = 23;
|
|
||||||
static constexpr BitsType signMask = 0x7FFFFFFFU;
|
|
||||||
static constexpr uint32_t exponentOffset = 127;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct FloatProperties<double> {
|
|
||||||
typedef uint64_t BitsType;
|
|
||||||
static_assert(sizeof(BitsType) == sizeof(double),
|
|
||||||
"Unexpected size of 'double' type.");
|
|
||||||
|
|
||||||
static constexpr uint32_t mantissaWidth = 52;
|
|
||||||
static constexpr BitsType signMask = 0x7FFFFFFFFFFFFFFFULL;
|
|
||||||
static constexpr uint32_t exponentOffset = 1023;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> typename FloatProperties<T>::BitsType getBits(T x) {
|
|
||||||
using BitsType = typename FloatProperties<T>::BitsType;
|
|
||||||
return *reinterpret_cast<BitsType *>(&x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the zero adjusted exponent value of abs(x).
|
|
||||||
template <typename T> int getExponent(T x) {
|
|
||||||
using Properties = FloatProperties<T>;
|
|
||||||
using BitsType = typename Properties::BitsType;
|
|
||||||
BitsType bits = *reinterpret_cast<BitsType *>(&x);
|
|
||||||
bits &= Properties::signMask; // Zero the sign bit.
|
|
||||||
int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa.
|
|
||||||
e -= Properties::exponentOffset; // Zero adjust.
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MPFRNumber {
|
class MPFRNumber {
|
||||||
// A precision value which allows sufficiently large additional
|
// A precision value which allows sufficiently large additional
|
||||||
// precision even compared to double precision floating point values.
|
// precision even compared to double precision floating point values.
|
||||||
|
@ -94,7 +58,7 @@ public:
|
||||||
template <typename XType> MPFRNumber(XType x, const Tolerance &t) {
|
template <typename XType> MPFRNumber(XType x, const Tolerance &t) {
|
||||||
mpfr_init2(value, mpfrPrecision);
|
mpfr_init2(value, mpfrPrecision);
|
||||||
mpfr_set_zero(value, 1); // Set to positive zero.
|
mpfr_set_zero(value, 1); // Set to positive zero.
|
||||||
MPFRNumber xExponent(getExponent(x));
|
MPFRNumber xExponent(fputil::getExponent(x));
|
||||||
// E = 2^E
|
// E = 2^E
|
||||||
mpfr_exp2(xExponent.value, xExponent.value, MPFR_RNDN);
|
mpfr_exp2(xExponent.value, xExponent.value, MPFR_RNDN);
|
||||||
uint32_t bitMask = 1 << (t.width - 1);
|
uint32_t bitMask = 1 << (t.width - 1);
|
||||||
|
@ -170,15 +134,18 @@ namespace internal {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void MPFRMatcher<T>::explainError(testutils::StreamWrapper &OS) {
|
void MPFRMatcher<T>::explainError(testutils::StreamWrapper &OS) {
|
||||||
|
using fputil::valueAsBits;
|
||||||
|
|
||||||
MPFRNumber mpfrResult(operation, input);
|
MPFRNumber mpfrResult(operation, input);
|
||||||
MPFRNumber mpfrInput(input);
|
MPFRNumber mpfrInput(input);
|
||||||
MPFRNumber mpfrMatchValue(matchValue);
|
MPFRNumber mpfrMatchValue(matchValue);
|
||||||
MPFRNumber mpfrToleranceValue(matchValue, tolerance);
|
MPFRNumber mpfrToleranceValue(matchValue, tolerance);
|
||||||
OS << "Match value not within tolerance value of MPFR result:\n"
|
OS << "Match value not within tolerance value of MPFR result:\n"
|
||||||
<< " Input decimal: " << mpfrInput.str() << '\n'
|
<< " Input decimal: " << mpfrInput.str() << '\n'
|
||||||
<< " Input bits: 0x" << llvm::utohexstr(getBits(input)) << '\n'
|
<< " Input bits: 0x" << llvm::utohexstr(valueAsBits(input)) << '\n'
|
||||||
<< " Match decimal: " << mpfrMatchValue.str() << '\n'
|
<< " Match decimal: " << mpfrMatchValue.str() << '\n'
|
||||||
<< " Match bits: 0x" << llvm::utohexstr(getBits(matchValue)) << '\n'
|
<< " Match bits: 0x" << llvm::utohexstr(valueAsBits(matchValue))
|
||||||
|
<< '\n'
|
||||||
<< " MPFR result: " << mpfrResult.str() << '\n'
|
<< " MPFR result: " << mpfrResult.str() << '\n'
|
||||||
<< "Tolerance value: " << mpfrToleranceValue.str() << '\n';
|
<< "Tolerance value: " << mpfrToleranceValue.str() << '\n';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue