Siva Chandra Reddy 5fedf7f420 [libc] Move implementations of cosf, sinf, sincosf to src/math directory.
NFC intended in the implementaton. Only mechanical changes to fit the LLVM
libc implementation standard have been done.

Math testing infrastructure has been added. This infrastructure compares the
results produced by the libc with the high precision results from MPFR.
Tests making use of this infrastructure have been added for cosf, sinf and
sincosf.

Reviewers: abrachet, phosek

Differential Revision: https://reviews.llvm.org/D76825
2020-04-16 08:46:10 -07:00

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