forked from OSchip/llvm-project
98 lines
2.8 KiB
C++
98 lines
2.8 KiB
C++
//===-- Utils which wrap MPFR ---------------------------------------------===//
|
|
//
|
|
// 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 "MPFRUtils.h"
|
|
|
|
#include <iostream>
|
|
#include <mpfr.h>
|
|
|
|
namespace __llvm_libc {
|
|
namespace testing {
|
|
namespace mpfr {
|
|
|
|
class MPFRNumber {
|
|
// A precision value which allows sufficiently large additional
|
|
// precision even compared to double precision floating point values.
|
|
static constexpr unsigned int mpfrPrecision = 96;
|
|
|
|
mpfr_t value;
|
|
|
|
public:
|
|
MPFRNumber() { mpfr_init2(value, mpfrPrecision); }
|
|
|
|
explicit MPFRNumber(float x) {
|
|
mpfr_init2(value, mpfrPrecision);
|
|
mpfr_set_flt(value, x, MPFR_RNDN);
|
|
}
|
|
|
|
MPFRNumber(const MPFRNumber &other) {
|
|
mpfr_set(value, other.value, MPFR_RNDN);
|
|
}
|
|
|
|
~MPFRNumber() { mpfr_clear(value); }
|
|
|
|
// Returns true if |other| is within the tolerance value |t| of this
|
|
// number.
|
|
bool isEqual(const MPFRNumber &other, const Tolerance &t) {
|
|
MPFRNumber tolerance(0.0);
|
|
uint32_t bitMask = 1 << (t.width - 1);
|
|
for (int exponent = -t.basePrecision; bitMask > 0; bitMask >>= 1) {
|
|
--exponent;
|
|
if (t.bits & bitMask) {
|
|
MPFRNumber delta;
|
|
mpfr_set_ui_2exp(delta.value, 1, exponent, MPFR_RNDN);
|
|
mpfr_add(tolerance.value, tolerance.value, delta.value, MPFR_RNDN);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// These functions are useful for debugging.
|
|
float asFloat() const { return mpfr_get_flt(value, MPFR_RNDN); }
|
|
double asDouble() const { return mpfr_get_d(value, MPFR_RNDN); }
|
|
void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
|
|
|
|
public:
|
|
static MPFRNumber cos(float x) {
|
|
MPFRNumber result;
|
|
MPFRNumber mpfrX(x);
|
|
mpfr_cos(result.value, mpfrX.value, MPFR_RNDN);
|
|
return result;
|
|
}
|
|
|
|
static MPFRNumber sin(float x) {
|
|
MPFRNumber result;
|
|
MPFRNumber mpfrX(x);
|
|
mpfr_sin(result.value, mpfrX.value, MPFR_RNDN);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
bool equalsCos(float input, float libcOutput, const Tolerance &t) {
|
|
MPFRNumber mpfrResult = MPFRNumber::cos(input);
|
|
MPFRNumber libcResult(libcOutput);
|
|
return mpfrResult.isEqual(libcResult, t);
|
|
}
|
|
|
|
bool equalsSin(float input, float libcOutput, const Tolerance &t) {
|
|
MPFRNumber mpfrResult = MPFRNumber::sin(input);
|
|
MPFRNumber libcResult(libcOutput);
|
|
return mpfrResult.isEqual(libcResult, t);
|
|
}
|
|
|
|
} // namespace mpfr
|
|
} // namespace testing
|
|
} // namespace __llvm_libc
|