21 changes: 8 additions & 13 deletions libc/test/src/math/sincosf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ using __llvm_libc::testing::sdcomp26094Values;

namespace mpfr = __llvm_libc::testing::mpfr;

// 12 additional bits of precision over the base precision of a |float|
// value.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
3 * 0x1000 / 4};

TEST(SinCosfTest, SpecialNumbers) {
llvmlibc_errno = 0;
float sin, cos;
Expand Down Expand Up @@ -96,8 +91,8 @@ TEST(SinCosfTest, InFloatRange) {

float sin, cos;
__llvm_libc::sincosf(x, &sin, &cos);
ASSERT_MPFR_MATCH(mpfr::Operation::Cos, x, cos, tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, sin, tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Cos, x, cos, 1.0);
ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, sin, 1.0);
}
}

Expand All @@ -107,16 +102,16 @@ TEST(SinCosfTest, SmallValues) {
float x = valueFromBits(bits);
float result_cos, result_sin;
__llvm_libc::sincosf(x, &result_sin, &result_cos);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, result_cos, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result_sin, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, result_cos, 1.0);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result_sin, 1.0);
EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
EXPECT_EQ(bits, valueAsBits(result_sin));

bits = 0x00400000;
x = valueFromBits(bits);
__llvm_libc::sincosf(x, &result_sin, &result_cos);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, result_cos, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result_sin, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, result_cos, 1.0);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result_sin, 1.0);
EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
EXPECT_EQ(bits, valueAsBits(result_sin));
}
Expand All @@ -128,7 +123,7 @@ TEST(SinCosfTest, SDCOMP_26094) {
float x = valueFromBits(v);
float sin, cos;
__llvm_libc::sincosf(x, &sin, &cos);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, cos, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, sin, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Cos, x, cos, 1.0);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, sin, 1.0);
}
}
15 changes: 5 additions & 10 deletions libc/test/src/math/sinf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ using __llvm_libc::testing::sdcomp26094Values;

namespace mpfr = __llvm_libc::testing::mpfr;

// 12 additional bits of precision over the base precision of a |float|
// value.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
3 * 0x1000 / 4};

TEST(SinfTest, SpecialNumbers) {
llvmlibc_errno = 0;

Expand Down Expand Up @@ -81,27 +76,27 @@ TEST(SinfTest, InFloatRange) {
float x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), 1.0);
}
}

TEST(SinfTest, SpecificBitPatterns) {
float x = valueFromBits(0xc70d39a1);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), 1.0);
}

// For small values, sin(x) is x.
TEST(SinfTest, SmallValues) {
uint32_t bits = 0x17800000;
float x = valueFromBits(bits);
float result = __llvm_libc::sinf(x);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result, 1.0);
EXPECT_EQ(bits, valueAsBits(result));

bits = 0x00400000;
x = valueFromBits(bits);
result = __llvm_libc::sinf(x);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result, tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, result, 1.0);
EXPECT_EQ(bits, valueAsBits(result));
}

Expand All @@ -110,6 +105,6 @@ TEST(SinfTest, SmallValues) {
TEST(SinfTest, SDCOMP_26094) {
for (uint32_t v : sdcomp26094Values) {
float x = valueFromBits(v);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), tolerance);
EXPECT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), 1.0);
}
}
6 changes: 1 addition & 5 deletions libc/test/src/math/trunc_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ static const double nan = FPBits::buildNaN(1);
static const double inf = FPBits::inf();
static const double negInf = FPBits::negInf();

// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0,
0};
TEST(TruncTest, SpecialNumbers) {
EXPECT_FP_EQ(zero, __llvm_libc::trunc(zero));
EXPECT_FP_EQ(negZero, __llvm_libc::trunc(negZero));
Expand Down Expand Up @@ -78,7 +75,6 @@ TEST(TruncTest, InDoubleRange) {
if (isnan(x) || isinf(x))
continue;

ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::trunc(x),
tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::trunc(x), 0.0);
}
}
6 changes: 1 addition & 5 deletions libc/test/src/math/truncf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ static const float nan = FPBits::buildNaN(1);
static const float inf = FPBits::inf();
static const float negInf = FPBits::negInf();

// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0,
0};
TEST(TruncfTest, SpecialNumbers) {
EXPECT_FP_EQ(zero, __llvm_libc::truncf(zero));
EXPECT_FP_EQ(negZero, __llvm_libc::truncf(negZero));
Expand Down Expand Up @@ -78,7 +75,6 @@ TEST(TruncfTest, InFloatRange) {
if (isnan(x) || isinf(x))
continue;

ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::truncf(x),
tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::truncf(x), 0.0);
}
}
6 changes: 1 addition & 5 deletions libc/test/src/math/truncl_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ static const long double nan = FPBits::buildNaN(1);
static const long double inf = FPBits::inf();
static const long double negInf = FPBits::negInf();

// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0,
0};
TEST(TrunclTest, SpecialNumbers) {
EXPECT_FP_EQ(zero, __llvm_libc::truncl(zero));
EXPECT_FP_EQ(negZero, __llvm_libc::truncl(negZero));
Expand Down Expand Up @@ -78,7 +75,6 @@ TEST(TrunclTest, InLongDoubleRange) {
if (isnan(x) || isinf(x))
continue;

ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::truncl(x),
tolerance);
ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::truncl(x), 0.0);
}
}
60 changes: 2 additions & 58 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,6 @@ class MPFRNumber {
mpfr_set_sj(value, x, MPFR_RNDN);
}

template <typename XType> MPFRNumber(XType x, const Tolerance &t) {
mpfr_init2(value, mpfrPrecision);
mpfr_set_zero(value, 1); // Set to positive zero.
MPFRNumber xExponent(fputil::FPBits<XType>(x).getExponent());
// E = 2^E
mpfr_exp2(xExponent.value, xExponent.value, MPFR_RNDN);
uint32_t bitMask = 1 << (t.width - 1);
for (int n = -t.basePrecision; bitMask > 0; bitMask >>= 1) {
--n;
if (t.bits & bitMask) {
// delta = -n
MPFRNumber delta(n);

// delta = 2^(-n)
mpfr_exp2(delta.value, delta.value, MPFR_RNDN);

// delta = E * 2^(-n)
mpfr_mul(delta.value, delta.value, xExponent.value, MPFR_RNDN);

// tolerance += delta
mpfr_add(value, value, delta.value, MPFR_RNDN);
}
}
}

template <typename XType,
cpp::EnableIfType<cpp::IsFloatingPointType<XType>::Value, int> = 0>
MPFRNumber(Operation op, XType rawValue) {
Expand Down Expand Up @@ -135,18 +110,6 @@ class MPFRNumber {

~MPFRNumber() { mpfr_clear(value); }

// Returns true if |other| is within the |tolerance| value of this
// number.
bool isEqual(const MPFRNumber &other, const MPFRNumber &tolerance) const {
MPFRNumber difference;
if (mpfr_cmp(value, other.value) >= 0)
mpfr_sub(difference.value, value, other.value, MPFR_RNDN);
else
mpfr_sub(difference.value, other.value, value, MPFR_RNDN);

return mpfr_lessequal_p(difference.value, tolerance.value);
}

std::string str() const {
// 200 bytes should be more than sufficient to hold a 100-digit number
// plus additional bytes for the decimal point, '-' sign etc.
Expand Down Expand Up @@ -234,34 +197,15 @@ void MPFRMatcher<T>::explainError(testutils::StreamWrapper &OS) {
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded: ", mpfrResult.as<T>(), OS);
OS << '\n';
if (useULP) {
OS << " ULP error: " << std::to_string(mpfrResult.ulp(matchValue))
<< '\n';
} else {
MPFRNumber mpfrToleranceValue = MPFRNumber(matchValue, tolerance);
OS << "Tolerance value: " << mpfrToleranceValue.str() << '\n';
}
OS << " ULP error: " << std::to_string(mpfrResult.ulp(matchValue))
<< '\n';
}

template void MPFRMatcher<float>::explainError(testutils::StreamWrapper &);
template void MPFRMatcher<double>::explainError(testutils::StreamWrapper &);
template void
MPFRMatcher<long double>::explainError(testutils::StreamWrapper &);

template <typename T>
bool compare(Operation op, T input, T libcResult, const Tolerance &t) {
MPFRNumber mpfrResult(op, input);
MPFRNumber mpfrLibcResult(libcResult);
MPFRNumber mpfrToleranceValue(libcResult, t);

return mpfrResult.isEqual(mpfrLibcResult, mpfrToleranceValue);
};

template bool compare<float>(Operation, float, float, const Tolerance &);
template bool compare<double>(Operation, double, double, const Tolerance &);
template bool compare<long double>(Operation, long double, long double,
const Tolerance &);

template <typename T>
bool compare(Operation op, T input, T libcResult, double ulpError) {
// If the ulp error is exactly 0.5 (i.e a tie), we would check that the result
Expand Down
39 changes: 3 additions & 36 deletions libc/utils/MPFRWrapper/MPFRUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,6 @@ namespace __llvm_libc {
namespace testing {
namespace mpfr {

struct Tolerance {
// Number of bits used to represent the fractional
// part of a value of type 'float'.
static constexpr unsigned int floatPrecision = 23;

// Number of bits used to represent the fractional
// part of a value of type 'double'.
static constexpr unsigned int doublePrecision = 52;

// The base precision of the number. For example, for values of
// type float, the base precision is the value |floatPrecision|.
unsigned int basePrecision;

unsigned int width; // Number of valid LSB bits in |value|.

// The bits in the tolerance value. The tolerance value will be
// sum(bits[width - i] * 2 ^ (- basePrecision - i)) for |i| in
// range [1, width].
uint32_t bits;
};

enum class Operation : int {
Abs,
Ceil,
Expand All @@ -54,9 +33,6 @@ enum class Operation : int {

namespace internal {

template <typename T>
bool compare(Operation op, T input, T libcOutput, const Tolerance &t);

template <typename T>
bool compare(Operation op, T input, T libcOutput, double t);

Expand All @@ -66,23 +42,16 @@ template <typename T> class MPFRMatcher : public testing::Matcher<T> {

Operation operation;
T input;
Tolerance tolerance;
T matchValue;
double ulpTolerance;
bool useULP;

public:
MPFRMatcher(Operation op, T testInput, Tolerance &t)
: operation(op), input(testInput), tolerance(t), useULP(false) {}
MPFRMatcher(Operation op, T testInput, double ulpTolerance)
: operation(op), input(testInput), ulpTolerance(ulpTolerance),
useULP(true) {}
: operation(op), input(testInput), ulpTolerance(ulpTolerance) {}

bool match(T libcResult) {
matchValue = libcResult;
return (useULP
? internal::compare(operation, input, libcResult, ulpTolerance)
: internal::compare(operation, input, libcResult, tolerance));
return internal::compare(operation, input, libcResult, ulpTolerance);
}

void explainError(testutils::StreamWrapper &OS) override;
Expand All @@ -92,9 +61,7 @@ template <typename T> class MPFRMatcher : public testing::Matcher<T> {

template <typename T, typename U>
__attribute__((no_sanitize("address")))
typename cpp::EnableIfType<cpp::IsSameV<U, Tolerance> ||
cpp::IsSameV<U, double>,
internal::MPFRMatcher<T>>
typename cpp::EnableIfType<cpp::IsSameV<U, double>, internal::MPFRMatcher<T>>
getMPFRMatcher(Operation op, T input, U t) {
static_assert(
__llvm_libc::cpp::IsFloatingPointType<T>::Value,
Expand Down