
The function is implemented using the following Taylor series that's generated using [python-sympy](https://www.sympy.org/en/index.html), and it is very accurate for |x| $$\in [0, 0.5]$$ and has been verified using Geogebra. The range reduction is used for the rest range (0.5, 1]. $$ \frac{\arcsin(x)}{\pi} \approx \begin{aligned}[t] & 0.318309886183791x \\ & + 0.0530516476972984x^3 \\ & + 0.0238732414637843x^5 \\ & + 0.0142102627760621x^7 \\ & + 0.00967087327815336x^9 \\ & + 0.00712127941391293x^{11} \\ & + 0.00552355646848375x^{13} \\ & + 0.00444514782463692x^{15} \\ & + 0.00367705242846804x^{17} \\ & + 0.00310721681820837x^{19} + O(x^{21}) \end{aligned} $$ ## Geogebra graph  Closes #132210
581 lines
16 KiB
C++
581 lines
16 KiB
C++
//===-- Utils used by both MPCWrapper and MPFRWrapper----------------------===//
|
|
//
|
|
// 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 "MPCommon.h"
|
|
|
|
#include "src/__support/CPP/string_view.h"
|
|
#include "src/__support/FPUtil/bfloat16.h"
|
|
#include "src/__support/FPUtil/cast.h"
|
|
#include "src/__support/macros/config.h"
|
|
#include "src/__support/macros/properties/types.h"
|
|
|
|
namespace LIBC_NAMESPACE_DECL {
|
|
namespace testing {
|
|
namespace mpfr {
|
|
|
|
MPFRNumber::MPFRNumber() : mpfr_precision(256), mpfr_rounding(MPFR_RNDN) {
|
|
mpfr_init2(value, mpfr_precision);
|
|
}
|
|
|
|
MPFRNumber::MPFRNumber(const MPFRNumber &other)
|
|
: mpfr_precision(other.mpfr_precision), mpfr_rounding(other.mpfr_rounding) {
|
|
mpfr_init2(value, mpfr_precision);
|
|
mpfr_set(value, other.value, mpfr_rounding);
|
|
}
|
|
|
|
MPFRNumber::MPFRNumber(const MPFRNumber &other, unsigned int precision)
|
|
: mpfr_precision(precision), mpfr_rounding(other.mpfr_rounding) {
|
|
mpfr_init2(value, mpfr_precision);
|
|
mpfr_set(value, other.value, mpfr_rounding);
|
|
}
|
|
|
|
MPFRNumber::MPFRNumber(const mpfr_t x, unsigned int precision,
|
|
RoundingMode rounding)
|
|
: mpfr_precision(precision),
|
|
mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
|
|
mpfr_init2(value, mpfr_precision);
|
|
mpfr_set(value, x, mpfr_rounding);
|
|
}
|
|
|
|
MPFRNumber::~MPFRNumber() { mpfr_clear(value); }
|
|
|
|
MPFRNumber &MPFRNumber::operator=(const MPFRNumber &rhs) {
|
|
mpfr_precision = rhs.mpfr_precision;
|
|
mpfr_rounding = rhs.mpfr_rounding;
|
|
mpfr_set(value, rhs.value, mpfr_rounding);
|
|
return *this;
|
|
}
|
|
|
|
bool MPFRNumber::is_nan() const { return mpfr_nan_p(value); }
|
|
|
|
MPFRNumber MPFRNumber::abs() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_abs(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::acos() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_acos(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::acosh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_acosh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::acospi() const {
|
|
MPFRNumber result(*this);
|
|
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
mpfr_acospi(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
MPFRNumber value_acos(0.0, 1280);
|
|
mpfr_acos(value_acos.value, value, MPFR_RNDN);
|
|
MPFRNumber value_pi(0.0, 1280);
|
|
mpfr_const_pi(value_pi.value, MPFR_RNDN);
|
|
mpfr_div(result.value, value_acos.value, value_pi.value, mpfr_rounding);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::add(const MPFRNumber &b) const {
|
|
MPFRNumber result(*this);
|
|
mpfr_add(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::asin() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_asin(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::asinh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_asinh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::asinpi() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_asinpi(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::atan() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_atan(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::atan2(const MPFRNumber &b) {
|
|
MPFRNumber result(*this);
|
|
mpfr_atan2(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::atanh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_atanh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::cbrt() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_cbrt(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::ceil() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_ceil(result.value, value);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::cos() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_cos(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::cosh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_cosh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::cospi() const {
|
|
MPFRNumber result(*this);
|
|
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
mpfr_cospi(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
if (mpfr_integer_p(value)) {
|
|
mpz_t integer;
|
|
mpz_init(integer);
|
|
mpfr_get_z(integer, value, mpfr_rounding);
|
|
|
|
int d = mpz_tstbit(integer, 0);
|
|
mpfr_set_si(result.value, d ? -1 : 1, mpfr_rounding);
|
|
mpz_clear(integer);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber value_pi(0.0, 1280);
|
|
mpfr_const_pi(value_pi.value, MPFR_RNDN);
|
|
mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
|
|
mpfr_cos(result.value, value_pi.value, mpfr_rounding);
|
|
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::erf() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_erf(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::exp() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_exp(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::exp2() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_exp2(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::exp2m1() const {
|
|
// TODO: Only use mpfr_exp2m1 once CI and buildbots get MPFR >= 4.2.0.
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
MPFRNumber result(*this);
|
|
mpfr_exp2m1(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
unsigned int prec = mpfr_precision * 3;
|
|
MPFRNumber result(*this, prec);
|
|
|
|
float f = mpfr_get_flt(abs().value, mpfr_rounding);
|
|
if (f > 0.5f && f < 0x1.0p30f) {
|
|
mpfr_exp2(result.value, value, mpfr_rounding);
|
|
mpfr_sub_ui(result.value, result.value, 1, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber ln2(2.0f, prec);
|
|
// log(2)
|
|
mpfr_log(ln2.value, ln2.value, mpfr_rounding);
|
|
// x * log(2)
|
|
mpfr_mul(result.value, value, ln2.value, mpfr_rounding);
|
|
// e^(x * log(2)) - 1
|
|
int ex = mpfr_expm1(result.value, result.value, mpfr_rounding);
|
|
mpfr_subnormalize(result.value, ex, mpfr_rounding);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::exp10() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_exp10(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::exp10m1() const {
|
|
// TODO: Only use mpfr_exp10m1 once CI and buildbots get MPFR >= 4.2.0.
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
MPFRNumber result(*this);
|
|
mpfr_exp10m1(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
unsigned int prec = mpfr_precision * 3;
|
|
MPFRNumber result(*this, prec);
|
|
|
|
MPFRNumber ln10(10.0f, prec);
|
|
// log(10)
|
|
mpfr_log(ln10.value, ln10.value, mpfr_rounding);
|
|
// x * log(10)
|
|
mpfr_mul(result.value, value, ln10.value, mpfr_rounding);
|
|
// e^(x * log(10)) - 1
|
|
int ex = mpfr_expm1(result.value, result.value, mpfr_rounding);
|
|
mpfr_subnormalize(result.value, ex, mpfr_rounding);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::expm1() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_expm1(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::div(const MPFRNumber &b) const {
|
|
MPFRNumber result(*this);
|
|
mpfr_div(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::floor() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_floor(result.value, value);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::fmod(const MPFRNumber &b) {
|
|
MPFRNumber result(*this);
|
|
mpfr_fmod(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::frexp(int &exp) {
|
|
MPFRNumber result(*this);
|
|
mpfr_exp_t resultExp;
|
|
mpfr_frexp(&resultExp, result.value, value, mpfr_rounding);
|
|
exp = static_cast<int>(resultExp);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::hypot(const MPFRNumber &b) {
|
|
MPFRNumber result(*this);
|
|
mpfr_hypot(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::log() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_log(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::log2() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_log2(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::log10() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_log10(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::log1p() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_log1p(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::pow(const MPFRNumber &b) {
|
|
MPFRNumber result(*this);
|
|
mpfr_pow(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::remquo(const MPFRNumber &divisor, int "ient) {
|
|
MPFRNumber remainder(*this);
|
|
long q;
|
|
mpfr_remquo(remainder.value, &q, value, divisor.value, mpfr_rounding);
|
|
quotient = static_cast<int>(q);
|
|
return remainder;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::round() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_round(result.value, value);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::roundeven() const {
|
|
MPFRNumber result(*this);
|
|
#if MPFR_VERSION_MAJOR >= 4
|
|
mpfr_roundeven(result.value, value);
|
|
#else
|
|
mpfr_rint(result.value, value, MPFR_RNDN);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
bool MPFRNumber::round_to_long(long &result) const {
|
|
// We first calculate the rounded value. This way, when converting
|
|
// to long using mpfr_get_si, the rounding direction of MPFR_RNDN
|
|
// (or any other rounding mode), does not have an influence.
|
|
MPFRNumber roundedValue = round();
|
|
mpfr_clear_erangeflag();
|
|
result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
|
|
return mpfr_erangeflag_p();
|
|
}
|
|
|
|
bool MPFRNumber::round_to_long(mpfr_rnd_t rnd, long &result) const {
|
|
MPFRNumber rint_result(*this);
|
|
mpfr_rint(rint_result.value, value, rnd);
|
|
return rint_result.round_to_long(result);
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::rint(mpfr_rnd_t rnd) const {
|
|
MPFRNumber result(*this);
|
|
mpfr_rint(result.value, value, rnd);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::mod_2pi() const {
|
|
MPFRNumber result(0.0, 1280);
|
|
MPFRNumber _2pi(0.0, 1280);
|
|
mpfr_const_pi(_2pi.value, MPFR_RNDN);
|
|
mpfr_mul_si(_2pi.value, _2pi.value, 2, MPFR_RNDN);
|
|
mpfr_fmod(result.value, value, _2pi.value, MPFR_RNDN);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::mod_pi_over_2() const {
|
|
MPFRNumber result(0.0, 1280);
|
|
MPFRNumber pi_over_2(0.0, 1280);
|
|
mpfr_const_pi(pi_over_2.value, MPFR_RNDN);
|
|
mpfr_mul_d(pi_over_2.value, pi_over_2.value, 0.5, MPFR_RNDN);
|
|
mpfr_fmod(result.value, value, pi_over_2.value, MPFR_RNDN);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::mod_pi_over_4() const {
|
|
MPFRNumber result(0.0, 1280);
|
|
MPFRNumber pi_over_4(0.0, 1280);
|
|
mpfr_const_pi(pi_over_4.value, MPFR_RNDN);
|
|
mpfr_mul_d(pi_over_4.value, pi_over_4.value, 0.25, MPFR_RNDN);
|
|
mpfr_fmod(result.value, value, pi_over_4.value, MPFR_RNDN);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::sin() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_sin(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::sinpi() const {
|
|
MPFRNumber result(*this);
|
|
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
mpfr_sinpi(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
if (mpfr_integer_p(value)) {
|
|
mpfr_set_si(result.value, 0, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber value_mul_two(*this);
|
|
mpfr_mul_si(value_mul_two.value, value, 2, MPFR_RNDN);
|
|
|
|
if (mpfr_integer_p(value_mul_two.value)) {
|
|
auto d = mpfr_get_si(value, MPFR_RNDD);
|
|
mpfr_set_si(result.value, (d & 1) ? -1 : 1, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber value_pi(0.0, 1280);
|
|
mpfr_const_pi(value_pi.value, MPFR_RNDN);
|
|
mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
|
|
mpfr_sin(result.value, value_pi.value, mpfr_rounding);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::sinh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_sinh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::sqrt() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_sqrt(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::sub(const MPFRNumber &b) const {
|
|
MPFRNumber result(*this);
|
|
mpfr_sub(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::tan() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_tan(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::tanh() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_tanh(result.value, value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::tanpi() const {
|
|
MPFRNumber result(*this);
|
|
|
|
#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
|
|
mpfr_tanpi(result.value, value, mpfr_rounding);
|
|
return result;
|
|
#else
|
|
MPFRNumber value_ret_exact(*this);
|
|
MPFRNumber value_one(*this);
|
|
mpfr_set_si(value_one.value, 1, MPFR_RNDN);
|
|
mpfr_fmod(value_ret_exact.value, value, value_one.value, mpfr_rounding);
|
|
mpfr_mul_si(value_ret_exact.value, value_ret_exact.value, 4, MPFR_RNDN);
|
|
|
|
if (mpfr_integer_p(value_ret_exact.value)) {
|
|
int mod = mpfr_get_si(value_ret_exact.value, MPFR_RNDN);
|
|
mod = (mod < 0 ? -1 * mod : mod);
|
|
|
|
switch (mod) {
|
|
case 0:
|
|
mpfr_set_si(result.value, 0, mpfr_rounding);
|
|
break;
|
|
case 1:
|
|
mpfr_set_si(result.value, (mpfr_signbit(value) ? -1 : 1), mpfr_rounding);
|
|
break;
|
|
case 2: {
|
|
auto d = mpfr_get_si(value, MPFR_RNDZ);
|
|
d += mpfr_sgn(value) > 0 ? 0 : 1;
|
|
mpfr_set_inf(result.value, (d & 1) ? -1 : 1);
|
|
break;
|
|
}
|
|
case 3:
|
|
mpfr_set_si(result.value, (mpfr_signbit(value) ? 1 : -1), mpfr_rounding);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber value_pi(0.0, 1280);
|
|
mpfr_const_pi(value_pi.value, MPFR_RNDN);
|
|
mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
|
|
mpfr_tan(result.value, value_pi.value, mpfr_rounding);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::trunc() const {
|
|
MPFRNumber result(*this);
|
|
mpfr_trunc(result.value, value);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::fma(const MPFRNumber &b, const MPFRNumber &c) {
|
|
MPFRNumber result(*this);
|
|
mpfr_fma(result.value, value, b.value, c.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
MPFRNumber MPFRNumber::mul(const MPFRNumber &b) {
|
|
MPFRNumber result(*this);
|
|
mpfr_mul(result.value, value, b.value, mpfr_rounding);
|
|
return result;
|
|
}
|
|
|
|
cpp::string MPFRNumber::str() const {
|
|
// 200 bytes should be more than sufficient to hold a 100-digit number
|
|
// plus additional bytes for the decimal point, '-' sign etc.
|
|
constexpr size_t printBufSize = 200;
|
|
char buffer[printBufSize];
|
|
mpfr_snprintf(buffer, printBufSize, "%100.50Rf", value);
|
|
cpp::string_view view(buffer);
|
|
// Trim whitespaces
|
|
const char whitespace = ' ';
|
|
while (!view.empty() && view.front() == whitespace)
|
|
view.remove_prefix(1);
|
|
while (!view.empty() && view.back() == whitespace)
|
|
view.remove_suffix(1);
|
|
return cpp::string(view.data());
|
|
}
|
|
|
|
void MPFRNumber::dump(const char *msg) const {
|
|
mpfr_printf("%s%.128g\n", msg, value);
|
|
}
|
|
|
|
template <> float MPFRNumber::as<float>() const {
|
|
return mpfr_get_flt(value, mpfr_rounding);
|
|
}
|
|
|
|
template <> double MPFRNumber::as<double>() const {
|
|
return mpfr_get_d(value, mpfr_rounding);
|
|
}
|
|
|
|
template <> long double MPFRNumber::as<long double>() const {
|
|
return mpfr_get_ld(value, mpfr_rounding);
|
|
}
|
|
|
|
#ifdef LIBC_TYPES_HAS_FLOAT16
|
|
template <> float16 MPFRNumber::as<float16>() const {
|
|
// TODO: Either prove that this cast won't cause double-rounding errors, or
|
|
// find a better way to get a float16.
|
|
return fputil::cast<float16>(mpfr_get_d(value, mpfr_rounding));
|
|
}
|
|
#endif
|
|
|
|
#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
|
|
template <> float128 MPFRNumber::as<float128>() const {
|
|
return mpfr_get_float128(value, mpfr_rounding);
|
|
}
|
|
#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
|
|
|
|
template <> bfloat16 MPFRNumber::as<bfloat16>() const {
|
|
return fputil::cast<bfloat16>(mpfr_get_flt(value, mpfr_rounding));
|
|
}
|
|
|
|
} // namespace mpfr
|
|
} // namespace testing
|
|
} // namespace LIBC_NAMESPACE_DECL
|