15fedf7f4SSiva Chandra Reddy //===-- Utils which wrap MPFR ---------------------------------------------===//
25fedf7f4SSiva Chandra Reddy //
35fedf7f4SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45fedf7f4SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
55fedf7f4SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65fedf7f4SSiva Chandra Reddy //
75fedf7f4SSiva Chandra Reddy //===----------------------------------------------------------------------===//
85fedf7f4SSiva Chandra Reddy
95fedf7f4SSiva Chandra Reddy #include "MPFRUtils.h"
105fedf7f4SSiva Chandra Reddy
11f362aea4SSiva Chandra Reddy #include "src/__support/CPP/StringView.h"
12c120edc7SMichael Jones #include "src/__support/FPUtil/FPBits.h"
13c386d6ebSTue Ly #include "src/__support/FPUtil/PlatformDefs.h"
14fe953b15SGuillaume Chatelet #include "utils/UnitTest/FPMatcher.h"
1532a22a42SSiva Chandra Reddy
16dba74c68SSiva Chandra Reddy #include <cmath>
17cce65077STue Ly #include <fenv.h>
183f4674a5SSiva Chandra Reddy #include <memory>
198cd81274STue Ly #include <sstream>
20a7e11496SSiva Chandra Reddy #include <stdint.h>
21d69cbd82SSiva Chandra Reddy #include <string>
225fedf7f4SSiva Chandra Reddy
23fb542b0bSSiva Chandra Reddy #ifdef CUSTOM_MPFR_INCLUDER
24fb542b0bSSiva Chandra Reddy // Some downstream repos are monoliths carrying MPFR sources in their third
25fb542b0bSSiva Chandra Reddy // party directory. In such repos, including the MPFR header as
26fb542b0bSSiva Chandra Reddy // `#include <mpfr.h>` is either disallowed or not possible. If that is the
27fb542b0bSSiva Chandra Reddy // case, a file named `CustomMPFRIncluder.h` should be added through which the
28fb542b0bSSiva Chandra Reddy // MPFR header can be included in manner allowed in that repo.
29fb542b0bSSiva Chandra Reddy #include "CustomMPFRIncluder.h"
30fb542b0bSSiva Chandra Reddy #else
31fb542b0bSSiva Chandra Reddy #include <mpfr.h>
32fb542b0bSSiva Chandra Reddy #endif
33fb542b0bSSiva Chandra Reddy
3413901826SSiva Chandra Reddy template <typename T> using FPBits = __llvm_libc::fputil::FPBits<T>;
3513901826SSiva Chandra Reddy
365fedf7f4SSiva Chandra Reddy namespace __llvm_libc {
375fedf7f4SSiva Chandra Reddy namespace testing {
385fedf7f4SSiva Chandra Reddy namespace mpfr {
395fedf7f4SSiva Chandra Reddy
404726bec8STue Ly template <typename T> struct Precision;
414726bec8STue Ly
424726bec8STue Ly template <> struct Precision<float> {
4360509623SSiva Chandra Reddy static constexpr unsigned int VALUE = 24;
444726bec8STue Ly };
454726bec8STue Ly
464726bec8STue Ly template <> struct Precision<double> {
4760509623SSiva Chandra Reddy static constexpr unsigned int VALUE = 53;
484726bec8STue Ly };
494726bec8STue Ly
50c386d6ebSTue Ly #if defined(LONG_DOUBLE_IS_DOUBLE)
51c386d6ebSTue Ly template <> struct Precision<long double> {
52c386d6ebSTue Ly static constexpr unsigned int VALUE = 53;
53c386d6ebSTue Ly };
54c386d6ebSTue Ly #elif defined(SPECIAL_X86_LONG_DOUBLE)
554726bec8STue Ly template <> struct Precision<long double> {
5660509623SSiva Chandra Reddy static constexpr unsigned int VALUE = 64;
574726bec8STue Ly };
584726bec8STue Ly #else
594726bec8STue Ly template <> struct Precision<long double> {
6060509623SSiva Chandra Reddy static constexpr unsigned int VALUE = 113;
614726bec8STue Ly };
624726bec8STue Ly #endif
634726bec8STue Ly
645fedf7f4SSiva Chandra Reddy // A precision value which allows sufficiently large additional
65cce65077STue Ly // precision compared to the floating point precision.
66cce65077STue Ly template <typename T> struct ExtraPrecision;
67cce65077STue Ly
68cce65077STue Ly template <> struct ExtraPrecision<float> {
69cce65077STue Ly static constexpr unsigned int VALUE = 128;
70cce65077STue Ly };
71cce65077STue Ly
72cce65077STue Ly template <> struct ExtraPrecision<double> {
73cce65077STue Ly static constexpr unsigned int VALUE = 256;
74cce65077STue Ly };
75cce65077STue Ly
76cce65077STue Ly template <> struct ExtraPrecision<long double> {
77cce65077STue Ly static constexpr unsigned int VALUE = 256;
78cce65077STue Ly };
79cce65077STue Ly
80cce65077STue Ly // If the ulp tolerance is less than or equal to 0.5, we would check that the
81cce65077STue Ly // result is rounded correctly with respect to the rounding mode by using the
82cce65077STue Ly // same precision as the inputs.
83cce65077STue Ly template <typename T>
get_precision(double ulp_tolerance)84cce65077STue Ly static inline unsigned int get_precision(double ulp_tolerance) {
85cce65077STue Ly if (ulp_tolerance <= 0.5) {
86cce65077STue Ly return Precision<T>::VALUE;
87cce65077STue Ly } else {
88cce65077STue Ly return ExtraPrecision<T>::VALUE;
89cce65077STue Ly }
90cce65077STue Ly }
91cce65077STue Ly
get_mpfr_rounding_mode(RoundingMode mode)92cce65077STue Ly static inline mpfr_rnd_t get_mpfr_rounding_mode(RoundingMode mode) {
93cce65077STue Ly switch (mode) {
94cce65077STue Ly case RoundingMode::Upward:
95cce65077STue Ly return MPFR_RNDU;
96cce65077STue Ly break;
97cce65077STue Ly case RoundingMode::Downward:
98cce65077STue Ly return MPFR_RNDD;
99cce65077STue Ly break;
100cce65077STue Ly case RoundingMode::TowardZero:
101cce65077STue Ly return MPFR_RNDZ;
102cce65077STue Ly break;
103cce65077STue Ly case RoundingMode::Nearest:
104cce65077STue Ly return MPFR_RNDN;
105cce65077STue Ly break;
106cce65077STue Ly }
107cce65077STue Ly }
108cce65077STue Ly
109cce65077STue Ly class MPFRNumber {
11060509623SSiva Chandra Reddy unsigned int mpfr_precision;
111cce65077STue Ly mpfr_rnd_t mpfr_rounding;
1125fedf7f4SSiva Chandra Reddy
1135fedf7f4SSiva Chandra Reddy mpfr_t value;
1145fedf7f4SSiva Chandra Reddy
1155fedf7f4SSiva Chandra Reddy public:
MPFRNumber()116cce65077STue Ly MPFRNumber() : mpfr_precision(256), mpfr_rounding(MPFR_RNDN) {
117cce65077STue Ly mpfr_init2(value, mpfr_precision);
118cce65077STue Ly }
1195fedf7f4SSiva Chandra Reddy
120d69cbd82SSiva Chandra Reddy // We use explicit EnableIf specializations to disallow implicit
121d69cbd82SSiva Chandra Reddy // conversions. Implicit conversions can potentially lead to loss of
122d69cbd82SSiva Chandra Reddy // precision.
123d69cbd82SSiva Chandra Reddy template <typename XType,
124d69cbd82SSiva Chandra Reddy cpp::EnableIfType<cpp::IsSame<float, XType>::Value, int> = 0>
MPFRNumber(XType x,int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)125cce65077STue Ly explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
126cce65077STue Ly RoundingMode rounding = RoundingMode::Nearest)
127cce65077STue Ly : mpfr_precision(precision),
128cce65077STue Ly mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
12960509623SSiva Chandra Reddy mpfr_init2(value, mpfr_precision);
130cce65077STue Ly mpfr_set_flt(value, x, mpfr_rounding);
1315fedf7f4SSiva Chandra Reddy }
1325fedf7f4SSiva Chandra Reddy
133d69cbd82SSiva Chandra Reddy template <typename XType,
134d69cbd82SSiva Chandra Reddy cpp::EnableIfType<cpp::IsSame<double, XType>::Value, int> = 0>
MPFRNumber(XType x,int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)135cce65077STue Ly explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
136cce65077STue Ly RoundingMode rounding = RoundingMode::Nearest)
137cce65077STue Ly : mpfr_precision(precision),
138cce65077STue Ly mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
13960509623SSiva Chandra Reddy mpfr_init2(value, mpfr_precision);
140cce65077STue Ly mpfr_set_d(value, x, mpfr_rounding);
141d69cbd82SSiva Chandra Reddy }
142d69cbd82SSiva Chandra Reddy
143d69cbd82SSiva Chandra Reddy template <typename XType,
14413901826SSiva Chandra Reddy cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
MPFRNumber(XType x,int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)145cce65077STue Ly explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
146cce65077STue Ly RoundingMode rounding = RoundingMode::Nearest)
147cce65077STue Ly : mpfr_precision(precision),
148cce65077STue Ly mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
14960509623SSiva Chandra Reddy mpfr_init2(value, mpfr_precision);
150cce65077STue Ly mpfr_set_ld(value, x, mpfr_rounding);
15113901826SSiva Chandra Reddy }
15213901826SSiva Chandra Reddy
15313901826SSiva Chandra Reddy template <typename XType,
154a7e11496SSiva Chandra Reddy cpp::EnableIfType<cpp::IsIntegral<XType>::Value, int> = 0>
MPFRNumber(XType x,int precision=ExtraPrecision<float>::VALUE,RoundingMode rounding=RoundingMode::Nearest)155cce65077STue Ly explicit MPFRNumber(XType x, int precision = ExtraPrecision<float>::VALUE,
156cce65077STue Ly RoundingMode rounding = RoundingMode::Nearest)
157cce65077STue Ly : mpfr_precision(precision),
158cce65077STue Ly mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
15960509623SSiva Chandra Reddy mpfr_init2(value, mpfr_precision);
160cce65077STue Ly mpfr_set_sj(value, x, mpfr_rounding);
161a7e11496SSiva Chandra Reddy }
162a7e11496SSiva Chandra Reddy
MPFRNumber(const MPFRNumber & other)163cce65077STue Ly MPFRNumber(const MPFRNumber &other)
164cce65077STue Ly : mpfr_precision(other.mpfr_precision),
165cce65077STue Ly mpfr_rounding(other.mpfr_rounding) {
16660509623SSiva Chandra Reddy mpfr_init2(value, mpfr_precision);
167cce65077STue Ly mpfr_set(value, other.value, mpfr_rounding);
1685fedf7f4SSiva Chandra Reddy }
1695fedf7f4SSiva Chandra Reddy
~MPFRNumber()1700aea170bSGuillaume Chatelet ~MPFRNumber() { mpfr_clear(value); }
1711948acb6SSiva Chandra Reddy
operator =(const MPFRNumber & rhs)1723f4674a5SSiva Chandra Reddy MPFRNumber &operator=(const MPFRNumber &rhs) {
17360509623SSiva Chandra Reddy mpfr_precision = rhs.mpfr_precision;
174cce65077STue Ly mpfr_rounding = rhs.mpfr_rounding;
175cce65077STue Ly mpfr_set(value, rhs.value, mpfr_rounding);
1763f4674a5SSiva Chandra Reddy return *this;
1773f4674a5SSiva Chandra Reddy }
1783f4674a5SSiva Chandra Reddy
abs() const1793f4674a5SSiva Chandra Reddy MPFRNumber abs() const {
180cce65077STue Ly MPFRNumber result(*this);
181cce65077STue Ly mpfr_abs(result.value, value, mpfr_rounding);
1823f4674a5SSiva Chandra Reddy return result;
1833f4674a5SSiva Chandra Reddy }
1843f4674a5SSiva Chandra Reddy
ceil() const1853f4674a5SSiva Chandra Reddy MPFRNumber ceil() const {
186cce65077STue Ly MPFRNumber result(*this);
1873f4674a5SSiva Chandra Reddy mpfr_ceil(result.value, value);
1883f4674a5SSiva Chandra Reddy return result;
1893f4674a5SSiva Chandra Reddy }
1903f4674a5SSiva Chandra Reddy
cos() const1913f4674a5SSiva Chandra Reddy MPFRNumber cos() const {
192cce65077STue Ly MPFRNumber result(*this);
193cce65077STue Ly mpfr_cos(result.value, value, mpfr_rounding);
1943f4674a5SSiva Chandra Reddy return result;
1953f4674a5SSiva Chandra Reddy }
1963f4674a5SSiva Chandra Reddy
exp() const1973f4674a5SSiva Chandra Reddy MPFRNumber exp() const {
198cce65077STue Ly MPFRNumber result(*this);
199cce65077STue Ly mpfr_exp(result.value, value, mpfr_rounding);
2003f4674a5SSiva Chandra Reddy return result;
2013f4674a5SSiva Chandra Reddy }
2023f4674a5SSiva Chandra Reddy
exp2() const2033f4674a5SSiva Chandra Reddy MPFRNumber exp2() const {
204cce65077STue Ly MPFRNumber result(*this);
205cce65077STue Ly mpfr_exp2(result.value, value, mpfr_rounding);
2063f4674a5SSiva Chandra Reddy return result;
2073f4674a5SSiva Chandra Reddy }
2083f4674a5SSiva Chandra Reddy
expm1() const2094e5f8b4dSTue Ly MPFRNumber expm1() const {
210cce65077STue Ly MPFRNumber result(*this);
211cce65077STue Ly mpfr_expm1(result.value, value, mpfr_rounding);
2124e5f8b4dSTue Ly return result;
2134e5f8b4dSTue Ly }
2144e5f8b4dSTue Ly
floor() const2153f4674a5SSiva Chandra Reddy MPFRNumber floor() const {
216cce65077STue Ly MPFRNumber result(*this);
2173f4674a5SSiva Chandra Reddy mpfr_floor(result.value, value);
2183f4674a5SSiva Chandra Reddy return result;
2193f4674a5SSiva Chandra Reddy }
2203f4674a5SSiva Chandra Reddy
fmod(const MPFRNumber & b)221*b8e8012aSKirill Okhotnikov MPFRNumber fmod(const MPFRNumber &b) {
222*b8e8012aSKirill Okhotnikov MPFRNumber result(*this);
223*b8e8012aSKirill Okhotnikov mpfr_fmod(result.value, value, b.value, mpfr_rounding);
224*b8e8012aSKirill Okhotnikov return result;
225*b8e8012aSKirill Okhotnikov }
226*b8e8012aSKirill Okhotnikov
frexp(int & exp)2273f4674a5SSiva Chandra Reddy MPFRNumber frexp(int &exp) {
228cce65077STue Ly MPFRNumber result(*this);
2293f4674a5SSiva Chandra Reddy mpfr_exp_t resultExp;
230cce65077STue Ly mpfr_frexp(&resultExp, result.value, value, mpfr_rounding);
2313f4674a5SSiva Chandra Reddy exp = resultExp;
2323f4674a5SSiva Chandra Reddy return result;
2333f4674a5SSiva Chandra Reddy }
2343f4674a5SSiva Chandra Reddy
hypot(const MPFRNumber & b)235abf1c82dSTue Ly MPFRNumber hypot(const MPFRNumber &b) {
236cce65077STue Ly MPFRNumber result(*this);
237cce65077STue Ly mpfr_hypot(result.value, value, b.value, mpfr_rounding);
238abf1c82dSTue Ly return result;
239abf1c82dSTue Ly }
240abf1c82dSTue Ly
log() const241d08a801bSTue Ly MPFRNumber log() const {
242cce65077STue Ly MPFRNumber result(*this);
243cce65077STue Ly mpfr_log(result.value, value, mpfr_rounding);
244d08a801bSTue Ly return result;
245d08a801bSTue Ly }
246d08a801bSTue Ly
log2() const24763d2df00STue Ly MPFRNumber log2() const {
24863d2df00STue Ly MPFRNumber result(*this);
24963d2df00STue Ly mpfr_log2(result.value, value, mpfr_rounding);
25063d2df00STue Ly return result;
25163d2df00STue Ly }
25263d2df00STue Ly
log10() const253e581841eSTue Ly MPFRNumber log10() const {
254e581841eSTue Ly MPFRNumber result(*this);
255e581841eSTue Ly mpfr_log10(result.value, value, mpfr_rounding);
256e581841eSTue Ly return result;
257e581841eSTue Ly }
258e581841eSTue Ly
log1p() const2599e7688c7STue Ly MPFRNumber log1p() const {
2609e7688c7STue Ly MPFRNumber result(*this);
2619e7688c7STue Ly mpfr_log1p(result.value, value, mpfr_rounding);
2629e7688c7STue Ly return result;
2639e7688c7STue Ly }
2649e7688c7STue Ly
remquo(const MPFRNumber & divisor,int & quotient)2653f4674a5SSiva Chandra Reddy MPFRNumber remquo(const MPFRNumber &divisor, int "ient) {
266cce65077STue Ly MPFRNumber remainder(*this);
2673f4674a5SSiva Chandra Reddy long q;
268cce65077STue Ly mpfr_remquo(remainder.value, &q, value, divisor.value, mpfr_rounding);
2693f4674a5SSiva Chandra Reddy quotient = q;
2703f4674a5SSiva Chandra Reddy return remainder;
2713f4674a5SSiva Chandra Reddy }
2723f4674a5SSiva Chandra Reddy
round() const2733f4674a5SSiva Chandra Reddy MPFRNumber round() const {
274cce65077STue Ly MPFRNumber result(*this);
2753f4674a5SSiva Chandra Reddy mpfr_round(result.value, value);
2763f4674a5SSiva Chandra Reddy return result;
2773f4674a5SSiva Chandra Reddy }
2783f4674a5SSiva Chandra Reddy
round_to_long(long & result) const279cce65077STue Ly bool round_to_long(long &result) const {
2807aeb3804SSiva Chandra Reddy // We first calculate the rounded value. This way, when converting
2817aeb3804SSiva Chandra Reddy // to long using mpfr_get_si, the rounding direction of MPFR_RNDN
2827aeb3804SSiva Chandra Reddy // (or any other rounding mode), does not have an influence.
2837aeb3804SSiva Chandra Reddy MPFRNumber roundedValue = round();
2847aeb3804SSiva Chandra Reddy mpfr_clear_erangeflag();
2857aeb3804SSiva Chandra Reddy result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
2867aeb3804SSiva Chandra Reddy return mpfr_erangeflag_p();
2877aeb3804SSiva Chandra Reddy }
2887aeb3804SSiva Chandra Reddy
round_to_long(mpfr_rnd_t rnd,long & result) const289cce65077STue Ly bool round_to_long(mpfr_rnd_t rnd, long &result) const {
290cce65077STue Ly MPFRNumber rint_result(*this);
291ff6fd385SSiva Chandra Reddy mpfr_rint(rint_result.value, value, rnd);
292cce65077STue Ly return rint_result.round_to_long(result);
293ff6fd385SSiva Chandra Reddy }
294ff6fd385SSiva Chandra Reddy
rint(mpfr_rnd_t rnd) const295ff6fd385SSiva Chandra Reddy MPFRNumber rint(mpfr_rnd_t rnd) const {
296cce65077STue Ly MPFRNumber result(*this);
297ff6fd385SSiva Chandra Reddy mpfr_rint(result.value, value, rnd);
298ff6fd385SSiva Chandra Reddy return result;
299ff6fd385SSiva Chandra Reddy }
300ff6fd385SSiva Chandra Reddy
mod_2pi() const301ca6b3542SSiva Chandra Reddy MPFRNumber mod_2pi() const {
302ca6b3542SSiva Chandra Reddy MPFRNumber result(0.0, 1280);
303ca6b3542SSiva Chandra Reddy MPFRNumber _2pi(0.0, 1280);
304ca6b3542SSiva Chandra Reddy mpfr_const_pi(_2pi.value, MPFR_RNDN);
305ca6b3542SSiva Chandra Reddy mpfr_mul_si(_2pi.value, _2pi.value, 2, MPFR_RNDN);
306ca6b3542SSiva Chandra Reddy mpfr_fmod(result.value, value, _2pi.value, MPFR_RNDN);
307ca6b3542SSiva Chandra Reddy return result;
308ca6b3542SSiva Chandra Reddy }
309ca6b3542SSiva Chandra Reddy
mod_pi_over_2() const310ca6b3542SSiva Chandra Reddy MPFRNumber mod_pi_over_2() const {
311ca6b3542SSiva Chandra Reddy MPFRNumber result(0.0, 1280);
312ca6b3542SSiva Chandra Reddy MPFRNumber pi_over_2(0.0, 1280);
313ca6b3542SSiva Chandra Reddy mpfr_const_pi(pi_over_2.value, MPFR_RNDN);
314ca6b3542SSiva Chandra Reddy mpfr_mul_d(pi_over_2.value, pi_over_2.value, 0.5, MPFR_RNDN);
315ca6b3542SSiva Chandra Reddy mpfr_fmod(result.value, value, pi_over_2.value, MPFR_RNDN);
316ca6b3542SSiva Chandra Reddy return result;
317ca6b3542SSiva Chandra Reddy }
318ca6b3542SSiva Chandra Reddy
mod_pi_over_4() const319ca6b3542SSiva Chandra Reddy MPFRNumber mod_pi_over_4() const {
320ca6b3542SSiva Chandra Reddy MPFRNumber result(0.0, 1280);
321ca6b3542SSiva Chandra Reddy MPFRNumber pi_over_4(0.0, 1280);
322ca6b3542SSiva Chandra Reddy mpfr_const_pi(pi_over_4.value, MPFR_RNDN);
323ca6b3542SSiva Chandra Reddy mpfr_mul_d(pi_over_4.value, pi_over_4.value, 0.25, MPFR_RNDN);
324ca6b3542SSiva Chandra Reddy mpfr_fmod(result.value, value, pi_over_4.value, MPFR_RNDN);
325ca6b3542SSiva Chandra Reddy return result;
326ca6b3542SSiva Chandra Reddy }
327ca6b3542SSiva Chandra Reddy
sin() const3283f4674a5SSiva Chandra Reddy MPFRNumber sin() const {
329cce65077STue Ly MPFRNumber result(*this);
330cce65077STue Ly mpfr_sin(result.value, value, mpfr_rounding);
3313f4674a5SSiva Chandra Reddy return result;
3323f4674a5SSiva Chandra Reddy }
3333f4674a5SSiva Chandra Reddy
sqrt() const3343f4674a5SSiva Chandra Reddy MPFRNumber sqrt() const {
335cce65077STue Ly MPFRNumber result(*this);
336cce65077STue Ly mpfr_sqrt(result.value, value, mpfr_rounding);
3373f4674a5SSiva Chandra Reddy return result;
3383f4674a5SSiva Chandra Reddy }
3393f4674a5SSiva Chandra Reddy
tan() const340861dc759SSiva Chandra Reddy MPFRNumber tan() const {
341cce65077STue Ly MPFRNumber result(*this);
342cce65077STue Ly mpfr_tan(result.value, value, mpfr_rounding);
343861dc759SSiva Chandra Reddy return result;
344861dc759SSiva Chandra Reddy }
345861dc759SSiva Chandra Reddy
trunc() const3463f4674a5SSiva Chandra Reddy MPFRNumber trunc() const {
347cce65077STue Ly MPFRNumber result(*this);
3483f4674a5SSiva Chandra Reddy mpfr_trunc(result.value, value);
3493f4674a5SSiva Chandra Reddy return result;
3503f4674a5SSiva Chandra Reddy }
3515fedf7f4SSiva Chandra Reddy
fma(const MPFRNumber & b,const MPFRNumber & c)3524726bec8STue Ly MPFRNumber fma(const MPFRNumber &b, const MPFRNumber &c) {
3534726bec8STue Ly MPFRNumber result(*this);
354cce65077STue Ly mpfr_fma(result.value, value, b.value, c.value, mpfr_rounding);
3554726bec8STue Ly return result;
3564726bec8STue Ly }
3574726bec8STue Ly
str() const358d69cbd82SSiva Chandra Reddy std::string str() const {
359d69cbd82SSiva Chandra Reddy // 200 bytes should be more than sufficient to hold a 100-digit number
360d69cbd82SSiva Chandra Reddy // plus additional bytes for the decimal point, '-' sign etc.
361d69cbd82SSiva Chandra Reddy constexpr size_t printBufSize = 200;
362d69cbd82SSiva Chandra Reddy char buffer[printBufSize];
363d69cbd82SSiva Chandra Reddy mpfr_snprintf(buffer, printBufSize, "%100.50Rf", value);
364dbb131d5SSiva Chandra Reddy cpp::StringView view(buffer);
365dbb131d5SSiva Chandra Reddy view = view.trim(' ');
366dbb131d5SSiva Chandra Reddy return std::string(view.data());
367d69cbd82SSiva Chandra Reddy }
368d69cbd82SSiva Chandra Reddy
3695fedf7f4SSiva Chandra Reddy // These functions are useful for debugging.
3709887a70eSTue Ly template <typename T> T as() const;
3719887a70eSTue Ly
dump(const char * msg) const3725fedf7f4SSiva Chandra Reddy void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
3739887a70eSTue Ly
3749887a70eSTue Ly // Return the ULP (units-in-the-last-place) difference between the
3759887a70eSTue Ly // stored MPFR and a floating point number.
3769887a70eSTue Ly //
377dba74c68SSiva Chandra Reddy // We define ULP difference as follows:
378dba74c68SSiva Chandra Reddy // If exponents of this value and the |input| are same, then:
379dba74c68SSiva Chandra Reddy // ULP(this_value, input) = abs(this_value - input) / eps(input)
380dba74c68SSiva Chandra Reddy // else:
381dba74c68SSiva Chandra Reddy // max = max(abs(this_value), abs(input))
382dba74c68SSiva Chandra Reddy // min = min(abs(this_value), abs(input))
383dba74c68SSiva Chandra Reddy // maxExponent = exponent(max)
384dba74c68SSiva Chandra Reddy // ULP(this_value, input) = (max - 2^maxExponent) / eps(max) +
385dba74c68SSiva Chandra Reddy // (2^maxExponent - min) / eps(min)
3869887a70eSTue Ly //
3879887a70eSTue Ly // Remarks:
388dba74c68SSiva Chandra Reddy // 1. A ULP of 0.0 will imply that the value is correctly rounded.
3899887a70eSTue Ly // 2. We expect that this value and the value to be compared (the [input]
3909887a70eSTue Ly // argument) are reasonable close, and we will provide an upper bound
3919887a70eSTue Ly // of ULP value for testing. Morever, most of the fractional parts of
3929887a70eSTue Ly // ULP value do not matter much, so using double as the return type
3939887a70eSTue Ly // should be good enough.
394dba74c68SSiva Chandra Reddy // 3. For close enough values (values which don't diff in their exponent by
395dba74c68SSiva Chandra Reddy // not more than 1), a ULP difference of N indicates a bit distance
396dba74c68SSiva Chandra Reddy // of N between this number and [input].
397dba74c68SSiva Chandra Reddy // 4. A values of +0.0 and -0.0 are treated as equal.
3989887a70eSTue Ly template <typename T>
ulp(T input)3999887a70eSTue Ly cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, double> ulp(T input) {
400dba74c68SSiva Chandra Reddy T thisAsT = as<T>();
401ca6b3542SSiva Chandra Reddy if (thisAsT == input)
402ca6b3542SSiva Chandra Reddy return T(0.0);
403ca6b3542SSiva Chandra Reddy
4041c92911eSMichael Jones int thisExponent = fputil::FPBits<T>(thisAsT).get_exponent();
4051c92911eSMichael Jones int inputExponent = fputil::FPBits<T>(input).get_exponent();
40632568fc9STue Ly // Adjust the exponents for denormal numbers.
4071c92911eSMichael Jones if (fputil::FPBits<T>(thisAsT).get_unbiased_exponent() == 0)
40832568fc9STue Ly ++thisExponent;
4091c92911eSMichael Jones if (fputil::FPBits<T>(input).get_unbiased_exponent() == 0)
41032568fc9STue Ly ++inputExponent;
41132568fc9STue Ly
412dba74c68SSiva Chandra Reddy if (thisAsT * input < 0 || thisExponent == inputExponent) {
413dba74c68SSiva Chandra Reddy MPFRNumber inputMPFR(input);
414dba74c68SSiva Chandra Reddy mpfr_sub(inputMPFR.value, value, inputMPFR.value, MPFR_RNDN);
415dba74c68SSiva Chandra Reddy mpfr_abs(inputMPFR.value, inputMPFR.value, MPFR_RNDN);
41632568fc9STue Ly mpfr_mul_2si(inputMPFR.value, inputMPFR.value,
4171c92911eSMichael Jones -thisExponent + int(fputil::MantissaWidth<T>::VALUE),
41832568fc9STue Ly MPFR_RNDN);
419dba74c68SSiva Chandra Reddy return inputMPFR.as<double>();
4209887a70eSTue Ly }
4219887a70eSTue Ly
422dba74c68SSiva Chandra Reddy // If the control reaches here, it means that this number and input are
423dba74c68SSiva Chandra Reddy // of the same sign but different exponent. In such a case, ULP error is
424dba74c68SSiva Chandra Reddy // calculated as sum of two parts.
425dba74c68SSiva Chandra Reddy thisAsT = std::abs(thisAsT);
426dba74c68SSiva Chandra Reddy input = std::abs(input);
427dba74c68SSiva Chandra Reddy T min = thisAsT > input ? input : thisAsT;
428dba74c68SSiva Chandra Reddy T max = thisAsT > input ? thisAsT : input;
4291c92911eSMichael Jones int minExponent = fputil::FPBits<T>(min).get_exponent();
4301c92911eSMichael Jones int maxExponent = fputil::FPBits<T>(max).get_exponent();
43132568fc9STue Ly // Adjust the exponents for denormal numbers.
4321c92911eSMichael Jones if (fputil::FPBits<T>(min).get_unbiased_exponent() == 0)
43332568fc9STue Ly ++minExponent;
4341c92911eSMichael Jones if (fputil::FPBits<T>(max).get_unbiased_exponent() == 0)
43532568fc9STue Ly ++maxExponent;
4369887a70eSTue Ly
437dba74c68SSiva Chandra Reddy MPFRNumber minMPFR(min);
438dba74c68SSiva Chandra Reddy MPFRNumber maxMPFR(max);
439dba74c68SSiva Chandra Reddy
440dba74c68SSiva Chandra Reddy MPFRNumber pivot(uint32_t(1));
441dba74c68SSiva Chandra Reddy mpfr_mul_2si(pivot.value, pivot.value, maxExponent, MPFR_RNDN);
442dba74c68SSiva Chandra Reddy
443dba74c68SSiva Chandra Reddy mpfr_sub(minMPFR.value, pivot.value, minMPFR.value, MPFR_RNDN);
44432568fc9STue Ly mpfr_mul_2si(minMPFR.value, minMPFR.value,
4451c92911eSMichael Jones -minExponent + int(fputil::MantissaWidth<T>::VALUE),
44632568fc9STue Ly MPFR_RNDN);
447dba74c68SSiva Chandra Reddy
448dba74c68SSiva Chandra Reddy mpfr_sub(maxMPFR.value, maxMPFR.value, pivot.value, MPFR_RNDN);
44932568fc9STue Ly mpfr_mul_2si(maxMPFR.value, maxMPFR.value,
4501c92911eSMichael Jones -maxExponent + int(fputil::MantissaWidth<T>::VALUE),
45132568fc9STue Ly MPFR_RNDN);
452dba74c68SSiva Chandra Reddy
453dba74c68SSiva Chandra Reddy mpfr_add(minMPFR.value, minMPFR.value, maxMPFR.value, MPFR_RNDN);
454dba74c68SSiva Chandra Reddy return minMPFR.as<double>();
4559887a70eSTue Ly }
4565fedf7f4SSiva Chandra Reddy };
4575fedf7f4SSiva Chandra Reddy
as() const458c28a522fSGuillaume Chatelet template <> float MPFRNumber::as<float>() const {
459c28a522fSGuillaume Chatelet return mpfr_get_flt(value, mpfr_rounding);
460c28a522fSGuillaume Chatelet }
461c28a522fSGuillaume Chatelet
as() const462c28a522fSGuillaume Chatelet template <> double MPFRNumber::as<double>() const {
463c28a522fSGuillaume Chatelet return mpfr_get_d(value, mpfr_rounding);
464c28a522fSGuillaume Chatelet }
465c28a522fSGuillaume Chatelet
as() const466c28a522fSGuillaume Chatelet template <> long double MPFRNumber::as<long double>() const {
467c28a522fSGuillaume Chatelet return mpfr_get_ld(value, mpfr_rounding);
468c28a522fSGuillaume Chatelet }
469c28a522fSGuillaume Chatelet
470d69cbd82SSiva Chandra Reddy namespace internal {
471d69cbd82SSiva Chandra Reddy
4723f4674a5SSiva Chandra Reddy template <typename InputType>
4733f4674a5SSiva Chandra Reddy cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
unary_operation(Operation op,InputType input,unsigned int precision,RoundingMode rounding)474cce65077STue Ly unary_operation(Operation op, InputType input, unsigned int precision,
475cce65077STue Ly RoundingMode rounding) {
476cce65077STue Ly MPFRNumber mpfrInput(input, precision, rounding);
4773f4674a5SSiva Chandra Reddy switch (op) {
4783f4674a5SSiva Chandra Reddy case Operation::Abs:
4793f4674a5SSiva Chandra Reddy return mpfrInput.abs();
4803f4674a5SSiva Chandra Reddy case Operation::Ceil:
4813f4674a5SSiva Chandra Reddy return mpfrInput.ceil();
4823f4674a5SSiva Chandra Reddy case Operation::Cos:
4833f4674a5SSiva Chandra Reddy return mpfrInput.cos();
4843f4674a5SSiva Chandra Reddy case Operation::Exp:
4853f4674a5SSiva Chandra Reddy return mpfrInput.exp();
4863f4674a5SSiva Chandra Reddy case Operation::Exp2:
4873f4674a5SSiva Chandra Reddy return mpfrInput.exp2();
4884e5f8b4dSTue Ly case Operation::Expm1:
4894e5f8b4dSTue Ly return mpfrInput.expm1();
4903f4674a5SSiva Chandra Reddy case Operation::Floor:
4913f4674a5SSiva Chandra Reddy return mpfrInput.floor();
492d08a801bSTue Ly case Operation::Log:
493d08a801bSTue Ly return mpfrInput.log();
49463d2df00STue Ly case Operation::Log2:
49563d2df00STue Ly return mpfrInput.log2();
496e581841eSTue Ly case Operation::Log10:
497e581841eSTue Ly return mpfrInput.log10();
4989e7688c7STue Ly case Operation::Log1p:
4999e7688c7STue Ly return mpfrInput.log1p();
500ca6b3542SSiva Chandra Reddy case Operation::Mod2PI:
501ca6b3542SSiva Chandra Reddy return mpfrInput.mod_2pi();
502ca6b3542SSiva Chandra Reddy case Operation::ModPIOver2:
503ca6b3542SSiva Chandra Reddy return mpfrInput.mod_pi_over_2();
504ca6b3542SSiva Chandra Reddy case Operation::ModPIOver4:
505ca6b3542SSiva Chandra Reddy return mpfrInput.mod_pi_over_4();
5063f4674a5SSiva Chandra Reddy case Operation::Round:
5073f4674a5SSiva Chandra Reddy return mpfrInput.round();
5083f4674a5SSiva Chandra Reddy case Operation::Sin:
5093f4674a5SSiva Chandra Reddy return mpfrInput.sin();
5103f4674a5SSiva Chandra Reddy case Operation::Sqrt:
5113f4674a5SSiva Chandra Reddy return mpfrInput.sqrt();
512861dc759SSiva Chandra Reddy case Operation::Tan:
513861dc759SSiva Chandra Reddy return mpfrInput.tan();
5143f4674a5SSiva Chandra Reddy case Operation::Trunc:
5153f4674a5SSiva Chandra Reddy return mpfrInput.trunc();
5163f4674a5SSiva Chandra Reddy default:
5173f4674a5SSiva Chandra Reddy __builtin_unreachable();
5183f4674a5SSiva Chandra Reddy }
5193f4674a5SSiva Chandra Reddy }
5203f4674a5SSiva Chandra Reddy
5213f4674a5SSiva Chandra Reddy template <typename InputType>
5223f4674a5SSiva Chandra Reddy cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
unary_operation_two_outputs(Operation op,InputType input,int & output,unsigned int precision,RoundingMode rounding)523cce65077STue Ly unary_operation_two_outputs(Operation op, InputType input, int &output,
524cce65077STue Ly unsigned int precision, RoundingMode rounding) {
525cce65077STue Ly MPFRNumber mpfrInput(input, precision, rounding);
5263f4674a5SSiva Chandra Reddy switch (op) {
5273f4674a5SSiva Chandra Reddy case Operation::Frexp:
5283f4674a5SSiva Chandra Reddy return mpfrInput.frexp(output);
5293f4674a5SSiva Chandra Reddy default:
5303f4674a5SSiva Chandra Reddy __builtin_unreachable();
5313f4674a5SSiva Chandra Reddy }
5323f4674a5SSiva Chandra Reddy }
5333f4674a5SSiva Chandra Reddy
5343f4674a5SSiva Chandra Reddy template <typename InputType>
5353f4674a5SSiva Chandra Reddy cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
binary_operation_one_output(Operation op,InputType x,InputType y,unsigned int precision,RoundingMode rounding)536cce65077STue Ly binary_operation_one_output(Operation op, InputType x, InputType y,
537cce65077STue Ly unsigned int precision, RoundingMode rounding) {
538cce65077STue Ly MPFRNumber inputX(x, precision, rounding);
539cce65077STue Ly MPFRNumber inputY(y, precision, rounding);
540abf1c82dSTue Ly switch (op) {
541*b8e8012aSKirill Okhotnikov case Operation::Fmod:
542*b8e8012aSKirill Okhotnikov return inputX.fmod(inputY);
543abf1c82dSTue Ly case Operation::Hypot:
544abf1c82dSTue Ly return inputX.hypot(inputY);
545abf1c82dSTue Ly default:
546abf1c82dSTue Ly __builtin_unreachable();
547abf1c82dSTue Ly }
548abf1c82dSTue Ly }
549abf1c82dSTue Ly
550abf1c82dSTue Ly template <typename InputType>
551abf1c82dSTue Ly cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
binary_operation_two_outputs(Operation op,InputType x,InputType y,int & output,unsigned int precision,RoundingMode rounding)55260509623SSiva Chandra Reddy binary_operation_two_outputs(Operation op, InputType x, InputType y,
553cce65077STue Ly int &output, unsigned int precision,
554cce65077STue Ly RoundingMode rounding) {
555cce65077STue Ly MPFRNumber inputX(x, precision, rounding);
556cce65077STue Ly MPFRNumber inputY(y, precision, rounding);
5573f4674a5SSiva Chandra Reddy switch (op) {
5583f4674a5SSiva Chandra Reddy case Operation::RemQuo:
5593f4674a5SSiva Chandra Reddy return inputX.remquo(inputY, output);
5603f4674a5SSiva Chandra Reddy default:
5613f4674a5SSiva Chandra Reddy __builtin_unreachable();
5623f4674a5SSiva Chandra Reddy }
5633f4674a5SSiva Chandra Reddy }
5643f4674a5SSiva Chandra Reddy
5654726bec8STue Ly template <typename InputType>
5664726bec8STue Ly cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
ternary_operation_one_output(Operation op,InputType x,InputType y,InputType z,unsigned int precision,RoundingMode rounding)56760509623SSiva Chandra Reddy ternary_operation_one_output(Operation op, InputType x, InputType y,
568cce65077STue Ly InputType z, unsigned int precision,
569cce65077STue Ly RoundingMode rounding) {
5704726bec8STue Ly // For FMA function, we just need to compare with the mpfr_fma with the same
5714726bec8STue Ly // precision as InputType. Using higher precision as the intermediate results
5724726bec8STue Ly // to compare might incorrectly fail due to double-rounding errors.
573cce65077STue Ly MPFRNumber inputX(x, precision, rounding);
574cce65077STue Ly MPFRNumber inputY(y, precision, rounding);
575cce65077STue Ly MPFRNumber inputZ(z, precision, rounding);
5764726bec8STue Ly switch (op) {
5774726bec8STue Ly case Operation::Fma:
5784726bec8STue Ly return inputX.fma(inputY, inputZ);
5794726bec8STue Ly default:
5804726bec8STue Ly __builtin_unreachable();
5814726bec8STue Ly }
5824726bec8STue Ly }
5834726bec8STue Ly
5848cd81274STue Ly // Remark: For all the explain_*_error functions, we will use std::stringstream
5858cd81274STue Ly // to build the complete error messages before sending it to the outstream `OS`
5868cd81274STue Ly // once at the end. This will stop the error messages from interleaving when
5878cd81274STue Ly // the tests are running concurrently.
5883f4674a5SSiva Chandra Reddy template <typename T>
explain_unary_operation_single_output_error(Operation op,T input,T matchValue,double ulp_tolerance,RoundingMode rounding,testutils::StreamWrapper & OS)58960509623SSiva Chandra Reddy void explain_unary_operation_single_output_error(Operation op, T input,
59060509623SSiva Chandra Reddy T matchValue,
591cce65077STue Ly double ulp_tolerance,
592cce65077STue Ly RoundingMode rounding,
5933f4674a5SSiva Chandra Reddy testutils::StreamWrapper &OS) {
594cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
595cce65077STue Ly MPFRNumber mpfrInput(input, precision);
596cce65077STue Ly MPFRNumber mpfr_result;
597cce65077STue Ly mpfr_result = unary_operation(op, input, precision, rounding);
598d69cbd82SSiva Chandra Reddy MPFRNumber mpfrMatchValue(matchValue);
5998cd81274STue Ly std::stringstream ss;
6008cd81274STue Ly ss << "Match value not within tolerance value of MPFR result:\n"
6019887a70eSTue Ly << " Input decimal: " << mpfrInput.str() << '\n';
6028cd81274STue Ly __llvm_libc::fputil::testing::describeValue(" Input bits: ", input, ss);
6038cd81274STue Ly ss << '\n' << " Match decimal: " << mpfrMatchValue.str() << '\n';
6049887a70eSTue Ly __llvm_libc::fputil::testing::describeValue(" Match bits: ", matchValue,
6058cd81274STue Ly ss);
6068cd81274STue Ly ss << '\n' << " MPFR result: " << mpfr_result.str() << '\n';
6079887a70eSTue Ly __llvm_libc::fputil::testing::describeValue(
6088cd81274STue Ly " MPFR rounded: ", mpfr_result.as<T>(), ss);
6098cd81274STue Ly ss << '\n';
6108cd81274STue Ly ss << " ULP error: " << std::to_string(mpfr_result.ulp(matchValue))
6119887a70eSTue Ly << '\n';
6128cd81274STue Ly OS << ss.str();
6135fedf7f4SSiva Chandra Reddy }
6145fedf7f4SSiva Chandra Reddy
61513901826SSiva Chandra Reddy template void
61660509623SSiva Chandra Reddy explain_unary_operation_single_output_error<float>(Operation op, float, float,
617cce65077STue Ly double, RoundingMode,
6183f4674a5SSiva Chandra Reddy testutils::StreamWrapper &);
61960509623SSiva Chandra Reddy template void explain_unary_operation_single_output_error<double>(
620cce65077STue Ly Operation op, double, double, double, RoundingMode,
621cce65077STue Ly testutils::StreamWrapper &);
62260509623SSiva Chandra Reddy template void explain_unary_operation_single_output_error<long double>(
623cce65077STue Ly Operation op, long double, long double, double, RoundingMode,
624cce65077STue Ly testutils::StreamWrapper &);
625d69cbd82SSiva Chandra Reddy
626d69cbd82SSiva Chandra Reddy template <typename T>
explain_unary_operation_two_outputs_error(Operation op,T input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding,testutils::StreamWrapper & OS)62760509623SSiva Chandra Reddy void explain_unary_operation_two_outputs_error(
62860509623SSiva Chandra Reddy Operation op, T input, const BinaryOutput<T> &libc_result,
629cce65077STue Ly double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
630cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
631cce65077STue Ly MPFRNumber mpfrInput(input, precision);
6323f4674a5SSiva Chandra Reddy int mpfrIntResult;
633cce65077STue Ly MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
634cce65077STue Ly precision, rounding);
6358cd81274STue Ly std::stringstream ss;
6363f4674a5SSiva Chandra Reddy
63760509623SSiva Chandra Reddy if (mpfrIntResult != libc_result.i) {
6388cd81274STue Ly ss << "MPFR integral result: " << mpfrIntResult << '\n'
63960509623SSiva Chandra Reddy << "Libc integral result: " << libc_result.i << '\n';
6403f4674a5SSiva Chandra Reddy } else {
6418cd81274STue Ly ss << "Integral result from libc matches integral result from MPFR.\n";
6423f4674a5SSiva Chandra Reddy }
6433f4674a5SSiva Chandra Reddy
64460509623SSiva Chandra Reddy MPFRNumber mpfrMatchValue(libc_result.f);
6458cd81274STue Ly ss << "Libc floating point result is not within tolerance value of the MPFR "
6463f4674a5SSiva Chandra Reddy << "result.\n\n";
6473f4674a5SSiva Chandra Reddy
6488cd81274STue Ly ss << " Input decimal: " << mpfrInput.str() << "\n\n";
6493f4674a5SSiva Chandra Reddy
6508cd81274STue Ly ss << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
6513f4674a5SSiva Chandra Reddy __llvm_libc::fputil::testing::describeValue(
6528cd81274STue Ly " Libc floating point bits: ", libc_result.f, ss);
6538cd81274STue Ly ss << "\n\n";
6543f4674a5SSiva Chandra Reddy
6558cd81274STue Ly ss << " MPFR result: " << mpfr_result.str() << '\n';
6563f4674a5SSiva Chandra Reddy __llvm_libc::fputil::testing::describeValue(
6578cd81274STue Ly " MPFR rounded: ", mpfr_result.as<T>(), ss);
6588cd81274STue Ly ss << '\n'
6593f4674a5SSiva Chandra Reddy << " ULP error: "
66060509623SSiva Chandra Reddy << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
6618cd81274STue Ly OS << ss.str();
6623f4674a5SSiva Chandra Reddy }
6633f4674a5SSiva Chandra Reddy
66460509623SSiva Chandra Reddy template void explain_unary_operation_two_outputs_error<float>(
665cce65077STue Ly Operation, float, const BinaryOutput<float> &, double, RoundingMode,
666cce65077STue Ly testutils::StreamWrapper &);
667cce65077STue Ly template void explain_unary_operation_two_outputs_error<double>(
668cce65077STue Ly Operation, double, const BinaryOutput<double> &, double, RoundingMode,
6693f4674a5SSiva Chandra Reddy testutils::StreamWrapper &);
67060509623SSiva Chandra Reddy template void explain_unary_operation_two_outputs_error<long double>(
671cce65077STue Ly Operation, long double, const BinaryOutput<long double> &, double,
672cce65077STue Ly RoundingMode, testutils::StreamWrapper &);
6733f4674a5SSiva Chandra Reddy
6743f4674a5SSiva Chandra Reddy template <typename T>
explain_binary_operation_two_outputs_error(Operation op,const BinaryInput<T> & input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding,testutils::StreamWrapper & OS)67560509623SSiva Chandra Reddy void explain_binary_operation_two_outputs_error(
67660509623SSiva Chandra Reddy Operation op, const BinaryInput<T> &input,
677cce65077STue Ly const BinaryOutput<T> &libc_result, double ulp_tolerance,
678cce65077STue Ly RoundingMode rounding, testutils::StreamWrapper &OS) {
679cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
680cce65077STue Ly MPFRNumber mpfrX(input.x, precision);
681cce65077STue Ly MPFRNumber mpfrY(input.y, precision);
6823f4674a5SSiva Chandra Reddy int mpfrIntResult;
683cce65077STue Ly MPFRNumber mpfr_result = binary_operation_two_outputs(
684cce65077STue Ly op, input.x, input.y, mpfrIntResult, precision, rounding);
68560509623SSiva Chandra Reddy MPFRNumber mpfrMatchValue(libc_result.f);
6868cd81274STue Ly std::stringstream ss;
6873f4674a5SSiva Chandra Reddy
6888cd81274STue Ly ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
6893f4674a5SSiva Chandra Reddy << "MPFR integral result: " << mpfrIntResult << '\n'
69060509623SSiva Chandra Reddy << "Libc integral result: " << libc_result.i << '\n'
6913f4674a5SSiva Chandra Reddy << "Libc floating point result: " << mpfrMatchValue.str() << '\n'
69260509623SSiva Chandra Reddy << " MPFR result: " << mpfr_result.str() << '\n';
6933f4674a5SSiva Chandra Reddy __llvm_libc::fputil::testing::describeValue(
6948cd81274STue Ly "Libc floating point result bits: ", libc_result.f, ss);
6953f4674a5SSiva Chandra Reddy __llvm_libc::fputil::testing::describeValue(
6968cd81274STue Ly " MPFR rounded bits: ", mpfr_result.as<T>(), ss);
6978cd81274STue Ly ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
6988cd81274STue Ly OS << ss.str();
6993f4674a5SSiva Chandra Reddy }
7003f4674a5SSiva Chandra Reddy
70160509623SSiva Chandra Reddy template void explain_binary_operation_two_outputs_error<float>(
702cce65077STue Ly Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
703cce65077STue Ly RoundingMode, testutils::StreamWrapper &);
70460509623SSiva Chandra Reddy template void explain_binary_operation_two_outputs_error<double>(
7053f4674a5SSiva Chandra Reddy Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
706cce65077STue Ly double, RoundingMode, testutils::StreamWrapper &);
70760509623SSiva Chandra Reddy template void explain_binary_operation_two_outputs_error<long double>(
7083f4674a5SSiva Chandra Reddy Operation, const BinaryInput<long double> &,
709cce65077STue Ly const BinaryOutput<long double> &, double, RoundingMode,
710cce65077STue Ly testutils::StreamWrapper &);
7113f4674a5SSiva Chandra Reddy
7123f4674a5SSiva Chandra Reddy template <typename T>
explain_binary_operation_one_output_error(Operation op,const BinaryInput<T> & input,T libc_result,double ulp_tolerance,RoundingMode rounding,testutils::StreamWrapper & OS)713cce65077STue Ly void explain_binary_operation_one_output_error(
714cce65077STue Ly Operation op, const BinaryInput<T> &input, T libc_result,
715cce65077STue Ly double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
716cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
717cce65077STue Ly MPFRNumber mpfrX(input.x, precision);
718cce65077STue Ly MPFRNumber mpfrY(input.y, precision);
719abf1c82dSTue Ly FPBits<T> xbits(input.x);
720abf1c82dSTue Ly FPBits<T> ybits(input.y);
721cce65077STue Ly MPFRNumber mpfr_result =
722cce65077STue Ly binary_operation_one_output(op, input.x, input.y, precision, rounding);
72360509623SSiva Chandra Reddy MPFRNumber mpfrMatchValue(libc_result);
7248cd81274STue Ly std::stringstream ss;
725abf1c82dSTue Ly
7268cd81274STue Ly ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
727abf1c82dSTue Ly __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
7288cd81274STue Ly ss);
729abf1c82dSTue Ly __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
7308cd81274STue Ly ss);
731abf1c82dSTue Ly
7328cd81274STue Ly ss << "Libc result: " << mpfrMatchValue.str() << '\n'
73360509623SSiva Chandra Reddy << "MPFR result: " << mpfr_result.str() << '\n';
734abf1c82dSTue Ly __llvm_libc::fputil::testing::describeValue(
7358cd81274STue Ly "Libc floating point result bits: ", libc_result, ss);
736abf1c82dSTue Ly __llvm_libc::fputil::testing::describeValue(
7378cd81274STue Ly " MPFR rounded bits: ", mpfr_result.as<T>(), ss);
7388cd81274STue Ly ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
7398cd81274STue Ly OS << ss.str();
740abf1c82dSTue Ly }
741abf1c82dSTue Ly
74260509623SSiva Chandra Reddy template void explain_binary_operation_one_output_error<float>(
743cce65077STue Ly Operation, const BinaryInput<float> &, float, double, RoundingMode,
744abf1c82dSTue Ly testutils::StreamWrapper &);
745cce65077STue Ly template void explain_binary_operation_one_output_error<double>(
746cce65077STue Ly Operation, const BinaryInput<double> &, double, double, RoundingMode,
747cce65077STue Ly testutils::StreamWrapper &);
748cce65077STue Ly template void explain_binary_operation_one_output_error<long double>(
749cce65077STue Ly Operation, const BinaryInput<long double> &, long double, double,
750cce65077STue Ly RoundingMode, testutils::StreamWrapper &);
751abf1c82dSTue Ly
752abf1c82dSTue Ly template <typename T>
explain_ternary_operation_one_output_error(Operation op,const TernaryInput<T> & input,T libc_result,double ulp_tolerance,RoundingMode rounding,testutils::StreamWrapper & OS)753cce65077STue Ly void explain_ternary_operation_one_output_error(
754cce65077STue Ly Operation op, const TernaryInput<T> &input, T libc_result,
755cce65077STue Ly double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
756cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
757cce65077STue Ly MPFRNumber mpfrX(input.x, precision);
758cce65077STue Ly MPFRNumber mpfrY(input.y, precision);
759cce65077STue Ly MPFRNumber mpfrZ(input.z, precision);
7604726bec8STue Ly FPBits<T> xbits(input.x);
7614726bec8STue Ly FPBits<T> ybits(input.y);
7624726bec8STue Ly FPBits<T> zbits(input.z);
763cce65077STue Ly MPFRNumber mpfr_result = ternary_operation_one_output(
764cce65077STue Ly op, input.x, input.y, input.z, precision, rounding);
76560509623SSiva Chandra Reddy MPFRNumber mpfrMatchValue(libc_result);
7668cd81274STue Ly std::stringstream ss;
7674726bec8STue Ly
7688cd81274STue Ly ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
7694726bec8STue Ly << " z: " << mpfrZ.str() << '\n';
7704726bec8STue Ly __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
7718cd81274STue Ly ss);
7724726bec8STue Ly __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
7738cd81274STue Ly ss);
7744726bec8STue Ly __llvm_libc::fputil::testing::describeValue("Third input bits: ", input.z,
7758cd81274STue Ly ss);
7764726bec8STue Ly
7778cd81274STue Ly ss << "Libc result: " << mpfrMatchValue.str() << '\n'
77860509623SSiva Chandra Reddy << "MPFR result: " << mpfr_result.str() << '\n';
7794726bec8STue Ly __llvm_libc::fputil::testing::describeValue(
7808cd81274STue Ly "Libc floating point result bits: ", libc_result, ss);
7814726bec8STue Ly __llvm_libc::fputil::testing::describeValue(
7828cd81274STue Ly " MPFR rounded bits: ", mpfr_result.as<T>(), ss);
7838cd81274STue Ly ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
7848cd81274STue Ly OS << ss.str();
7854726bec8STue Ly }
7864726bec8STue Ly
78760509623SSiva Chandra Reddy template void explain_ternary_operation_one_output_error<float>(
788cce65077STue Ly Operation, const TernaryInput<float> &, float, double, RoundingMode,
789cce65077STue Ly testutils::StreamWrapper &);
79060509623SSiva Chandra Reddy template void explain_ternary_operation_one_output_error<double>(
791cce65077STue Ly Operation, const TernaryInput<double> &, double, double, RoundingMode,
7924726bec8STue Ly testutils::StreamWrapper &);
79360509623SSiva Chandra Reddy template void explain_ternary_operation_one_output_error<long double>(
794cce65077STue Ly Operation, const TernaryInput<long double> &, long double, double,
795cce65077STue Ly RoundingMode, testutils::StreamWrapper &);
7964726bec8STue Ly
7974726bec8STue Ly template <typename T>
compare_unary_operation_single_output(Operation op,T input,T libc_result,double ulp_tolerance,RoundingMode rounding)79860509623SSiva Chandra Reddy bool compare_unary_operation_single_output(Operation op, T input, T libc_result,
799cce65077STue Ly double ulp_tolerance,
800cce65077STue Ly RoundingMode rounding) {
801cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
802cce65077STue Ly MPFRNumber mpfr_result;
803cce65077STue Ly mpfr_result = unary_operation(op, input, precision, rounding);
80460509623SSiva Chandra Reddy double ulp = mpfr_result.ulp(libc_result);
805cce65077STue Ly return (ulp <= ulp_tolerance);
8069887a70eSTue Ly }
8079887a70eSTue Ly
80860509623SSiva Chandra Reddy template bool compare_unary_operation_single_output<float>(Operation, float,
809cce65077STue Ly float, double,
810cce65077STue Ly RoundingMode);
81160509623SSiva Chandra Reddy template bool compare_unary_operation_single_output<double>(Operation, double,
812cce65077STue Ly double, double,
813cce65077STue Ly RoundingMode);
814cce65077STue Ly template bool compare_unary_operation_single_output<long double>(
815cce65077STue Ly Operation, long double, long double, double, RoundingMode);
8163f4674a5SSiva Chandra Reddy
8173f4674a5SSiva Chandra Reddy template <typename T>
compare_unary_operation_two_outputs(Operation op,T input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding)81860509623SSiva Chandra Reddy bool compare_unary_operation_two_outputs(Operation op, T input,
81960509623SSiva Chandra Reddy const BinaryOutput<T> &libc_result,
820cce65077STue Ly double ulp_tolerance,
821cce65077STue Ly RoundingMode rounding) {
8223f4674a5SSiva Chandra Reddy int mpfrIntResult;
823cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
824cce65077STue Ly MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
825cce65077STue Ly precision, rounding);
82660509623SSiva Chandra Reddy double ulp = mpfr_result.ulp(libc_result.f);
8273f4674a5SSiva Chandra Reddy
82860509623SSiva Chandra Reddy if (mpfrIntResult != libc_result.i)
8293f4674a5SSiva Chandra Reddy return false;
8303f4674a5SSiva Chandra Reddy
831cce65077STue Ly return (ulp <= ulp_tolerance);
8323f4674a5SSiva Chandra Reddy }
8333f4674a5SSiva Chandra Reddy
834cce65077STue Ly template bool compare_unary_operation_two_outputs<float>(
835cce65077STue Ly Operation, float, const BinaryOutput<float> &, double, RoundingMode);
83660509623SSiva Chandra Reddy template bool compare_unary_operation_two_outputs<double>(
837cce65077STue Ly Operation, double, const BinaryOutput<double> &, double, RoundingMode);
83860509623SSiva Chandra Reddy template bool compare_unary_operation_two_outputs<long double>(
839cce65077STue Ly Operation, long double, const BinaryOutput<long double> &, double,
840cce65077STue Ly RoundingMode);
8413f4674a5SSiva Chandra Reddy
8423f4674a5SSiva Chandra Reddy template <typename T>
compare_binary_operation_two_outputs(Operation op,const BinaryInput<T> & input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding)84360509623SSiva Chandra Reddy bool compare_binary_operation_two_outputs(Operation op,
84460509623SSiva Chandra Reddy const BinaryInput<T> &input,
84560509623SSiva Chandra Reddy const BinaryOutput<T> &libc_result,
846cce65077STue Ly double ulp_tolerance,
847cce65077STue Ly RoundingMode rounding) {
8483f4674a5SSiva Chandra Reddy int mpfrIntResult;
849cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
850cce65077STue Ly MPFRNumber mpfr_result = binary_operation_two_outputs(
851cce65077STue Ly op, input.x, input.y, mpfrIntResult, precision, rounding);
85260509623SSiva Chandra Reddy double ulp = mpfr_result.ulp(libc_result.f);
8533f4674a5SSiva Chandra Reddy
85460509623SSiva Chandra Reddy if (mpfrIntResult != libc_result.i) {
8553f4674a5SSiva Chandra Reddy if (op == Operation::RemQuo) {
85660509623SSiva Chandra Reddy if ((0x7 & mpfrIntResult) != (0x7 & libc_result.i))
8573f4674a5SSiva Chandra Reddy return false;
8583f4674a5SSiva Chandra Reddy } else {
8593f4674a5SSiva Chandra Reddy return false;
8603f4674a5SSiva Chandra Reddy }
8613f4674a5SSiva Chandra Reddy }
8623f4674a5SSiva Chandra Reddy
863cce65077STue Ly return (ulp <= ulp_tolerance);
8643f4674a5SSiva Chandra Reddy }
8653f4674a5SSiva Chandra Reddy
86660509623SSiva Chandra Reddy template bool compare_binary_operation_two_outputs<float>(
867cce65077STue Ly Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
868cce65077STue Ly RoundingMode);
86960509623SSiva Chandra Reddy template bool compare_binary_operation_two_outputs<double>(
87060509623SSiva Chandra Reddy Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
871cce65077STue Ly double, RoundingMode);
87260509623SSiva Chandra Reddy template bool compare_binary_operation_two_outputs<long double>(
8733f4674a5SSiva Chandra Reddy Operation, const BinaryInput<long double> &,
874cce65077STue Ly const BinaryOutput<long double> &, double, RoundingMode);
8759887a70eSTue Ly
876abf1c82dSTue Ly template <typename T>
compare_binary_operation_one_output(Operation op,const BinaryInput<T> & input,T libc_result,double ulp_tolerance,RoundingMode rounding)87760509623SSiva Chandra Reddy bool compare_binary_operation_one_output(Operation op,
87860509623SSiva Chandra Reddy const BinaryInput<T> &input,
879cce65077STue Ly T libc_result, double ulp_tolerance,
880cce65077STue Ly RoundingMode rounding) {
881cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
882cce65077STue Ly MPFRNumber mpfr_result =
883cce65077STue Ly binary_operation_one_output(op, input.x, input.y, precision, rounding);
88460509623SSiva Chandra Reddy double ulp = mpfr_result.ulp(libc_result);
885abf1c82dSTue Ly
886cce65077STue Ly return (ulp <= ulp_tolerance);
887abf1c82dSTue Ly }
888abf1c82dSTue Ly
88960509623SSiva Chandra Reddy template bool compare_binary_operation_one_output<float>(
890cce65077STue Ly Operation, const BinaryInput<float> &, float, double, RoundingMode);
89160509623SSiva Chandra Reddy template bool compare_binary_operation_one_output<double>(
892cce65077STue Ly Operation, const BinaryInput<double> &, double, double, RoundingMode);
89360509623SSiva Chandra Reddy template bool compare_binary_operation_one_output<long double>(
894cce65077STue Ly Operation, const BinaryInput<long double> &, long double, double,
895cce65077STue Ly RoundingMode);
896abf1c82dSTue Ly
8974726bec8STue Ly template <typename T>
compare_ternary_operation_one_output(Operation op,const TernaryInput<T> & input,T libc_result,double ulp_tolerance,RoundingMode rounding)89860509623SSiva Chandra Reddy bool compare_ternary_operation_one_output(Operation op,
8994726bec8STue Ly const TernaryInput<T> &input,
900cce65077STue Ly T libc_result, double ulp_tolerance,
901cce65077STue Ly RoundingMode rounding) {
902cce65077STue Ly unsigned int precision = get_precision<T>(ulp_tolerance);
903cce65077STue Ly MPFRNumber mpfr_result = ternary_operation_one_output(
904cce65077STue Ly op, input.x, input.y, input.z, precision, rounding);
90560509623SSiva Chandra Reddy double ulp = mpfr_result.ulp(libc_result);
9064726bec8STue Ly
907cce65077STue Ly return (ulp <= ulp_tolerance);
9084726bec8STue Ly }
9094726bec8STue Ly
91060509623SSiva Chandra Reddy template bool compare_ternary_operation_one_output<float>(
911cce65077STue Ly Operation, const TernaryInput<float> &, float, double, RoundingMode);
91260509623SSiva Chandra Reddy template bool compare_ternary_operation_one_output<double>(
913cce65077STue Ly Operation, const TernaryInput<double> &, double, double, RoundingMode);
91460509623SSiva Chandra Reddy template bool compare_ternary_operation_one_output<long double>(
915cce65077STue Ly Operation, const TernaryInput<long double> &, long double, double,
916cce65077STue Ly RoundingMode);
917ff6fd385SSiva Chandra Reddy
918d69cbd82SSiva Chandra Reddy } // namespace internal
9195fedf7f4SSiva Chandra Reddy
round_to_long(T x,long & result)92060509623SSiva Chandra Reddy template <typename T> bool round_to_long(T x, long &result) {
9217aeb3804SSiva Chandra Reddy MPFRNumber mpfr(x);
922cce65077STue Ly return mpfr.round_to_long(result);
9237aeb3804SSiva Chandra Reddy }
9247aeb3804SSiva Chandra Reddy
92560509623SSiva Chandra Reddy template bool round_to_long<float>(float, long &);
92660509623SSiva Chandra Reddy template bool round_to_long<double>(double, long &);
92760509623SSiva Chandra Reddy template bool round_to_long<long double>(long double, long &);
9287aeb3804SSiva Chandra Reddy
round_to_long(T x,RoundingMode mode,long & result)92960509623SSiva Chandra Reddy template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
930ff6fd385SSiva Chandra Reddy MPFRNumber mpfr(x);
931cce65077STue Ly return mpfr.round_to_long(get_mpfr_rounding_mode(mode), result);
932ff6fd385SSiva Chandra Reddy }
933ff6fd385SSiva Chandra Reddy
93460509623SSiva Chandra Reddy template bool round_to_long<float>(float, RoundingMode, long &);
93560509623SSiva Chandra Reddy template bool round_to_long<double>(double, RoundingMode, long &);
93660509623SSiva Chandra Reddy template bool round_to_long<long double>(long double, RoundingMode, long &);
937ff6fd385SSiva Chandra Reddy
round(T x,RoundingMode mode)93860509623SSiva Chandra Reddy template <typename T> T round(T x, RoundingMode mode) {
939ff6fd385SSiva Chandra Reddy MPFRNumber mpfr(x);
940cce65077STue Ly MPFRNumber result = mpfr.rint(get_mpfr_rounding_mode(mode));
941ff6fd385SSiva Chandra Reddy return result.as<T>();
942ff6fd385SSiva Chandra Reddy }
943ff6fd385SSiva Chandra Reddy
94460509623SSiva Chandra Reddy template float round<float>(float, RoundingMode);
94560509623SSiva Chandra Reddy template double round<double>(double, RoundingMode);
94660509623SSiva Chandra Reddy template long double round<long double>(long double, RoundingMode);
947ff6fd385SSiva Chandra Reddy
9485fedf7f4SSiva Chandra Reddy } // namespace mpfr
9495fedf7f4SSiva Chandra Reddy } // namespace testing
9505fedf7f4SSiva Chandra Reddy } // namespace __llvm_libc
951