• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Utils which wrap MPFR ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "MPFRUtils.h"
10 
11 #include "src/__support/CPP/array.h"
12 #include "src/__support/CPP/string.h"
13 #include "src/__support/CPP/string_view.h"
14 #include "src/__support/CPP/stringstream.h"
15 #include "src/__support/FPUtil/FPBits.h"
16 #include "src/__support/FPUtil/cast.h"
17 #include "src/__support/FPUtil/fpbits_str.h"
18 #include "src/__support/macros/config.h"
19 #include "src/__support/macros/properties/types.h"
20 
21 #include <stdint.h>
22 
23 #include "mpfr_inc.h"
24 
25 template <typename T> using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
26 
27 namespace LIBC_NAMESPACE_DECL {
28 namespace testing {
29 namespace mpfr {
30 
31 // A precision value which allows sufficiently large additional
32 // precision compared to the floating point precision.
33 template <typename T> struct ExtraPrecision;
34 
35 #ifdef LIBC_TYPES_HAS_FLOAT16
36 template <> struct ExtraPrecision<float16> {
37   static constexpr unsigned int VALUE = 128;
38 };
39 #endif
40 
41 template <> struct ExtraPrecision<float> {
42   static constexpr unsigned int VALUE = 128;
43 };
44 
45 template <> struct ExtraPrecision<double> {
46   static constexpr unsigned int VALUE = 256;
47 };
48 
49 template <> struct ExtraPrecision<long double> {
50   static constexpr unsigned int VALUE = 256;
51 };
52 
53 // If the ulp tolerance is less than or equal to 0.5, we would check that the
54 // result is rounded correctly with respect to the rounding mode by using the
55 // same precision as the inputs.
56 template <typename T>
get_precision(double ulp_tolerance)57 static inline unsigned int get_precision(double ulp_tolerance) {
58   if (ulp_tolerance <= 0.5) {
59     return LIBC_NAMESPACE::fputil::FPBits<T>::FRACTION_LEN + 1;
60   } else {
61     return ExtraPrecision<T>::VALUE;
62   }
63 }
64 
get_mpfr_rounding_mode(RoundingMode mode)65 static inline mpfr_rnd_t get_mpfr_rounding_mode(RoundingMode mode) {
66   switch (mode) {
67   case RoundingMode::Upward:
68     return MPFR_RNDU;
69     break;
70   case RoundingMode::Downward:
71     return MPFR_RNDD;
72     break;
73   case RoundingMode::TowardZero:
74     return MPFR_RNDZ;
75     break;
76   case RoundingMode::Nearest:
77     return MPFR_RNDN;
78     break;
79   }
80   __builtin_unreachable();
81 }
82 
83 class MPFRNumber {
84   unsigned int mpfr_precision;
85   mpfr_rnd_t mpfr_rounding;
86 
87   mpfr_t value;
88 
89 public:
MPFRNumber()90   MPFRNumber() : mpfr_precision(256), mpfr_rounding(MPFR_RNDN) {
91     mpfr_init2(value, mpfr_precision);
92   }
93 
94   // We use explicit EnableIf specializations to disallow implicit
95   // conversions. Implicit conversions can potentially lead to loss of
96   // precision. We exceptionally allow implicit conversions from float16
97   // to float, as the MPFR API does not support float16, thus requiring
98   // conversion to a higher-precision format.
99   template <typename XType,
100             cpp::enable_if_t<cpp::is_same_v<float, XType>
101 #ifdef LIBC_TYPES_HAS_FLOAT16
102                                  || cpp::is_same_v<float16, XType>
103 #endif
104                              ,
105                              int> = 0>
MPFRNumber(XType x,unsigned int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)106   explicit MPFRNumber(XType x,
107                       unsigned int precision = ExtraPrecision<XType>::VALUE,
108                       RoundingMode rounding = RoundingMode::Nearest)
109       : mpfr_precision(precision),
110         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
111     mpfr_init2(value, mpfr_precision);
112     mpfr_set_flt(value, x, mpfr_rounding);
113   }
114 
115   template <typename XType,
116             cpp::enable_if_t<cpp::is_same_v<double, XType>, int> = 0>
MPFRNumber(XType x,unsigned int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)117   explicit MPFRNumber(XType x,
118                       unsigned int precision = ExtraPrecision<XType>::VALUE,
119                       RoundingMode rounding = RoundingMode::Nearest)
120       : mpfr_precision(precision),
121         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
122     mpfr_init2(value, mpfr_precision);
123     mpfr_set_d(value, x, mpfr_rounding);
124   }
125 
126   template <typename XType,
127             cpp::enable_if_t<cpp::is_same_v<long double, XType>, int> = 0>
MPFRNumber(XType x,unsigned int precision=ExtraPrecision<XType>::VALUE,RoundingMode rounding=RoundingMode::Nearest)128   explicit MPFRNumber(XType x,
129                       unsigned int precision = ExtraPrecision<XType>::VALUE,
130                       RoundingMode rounding = RoundingMode::Nearest)
131       : mpfr_precision(precision),
132         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
133     mpfr_init2(value, mpfr_precision);
134     mpfr_set_ld(value, x, mpfr_rounding);
135   }
136 
137   template <typename XType,
138             cpp::enable_if_t<cpp::is_integral_v<XType>, int> = 0>
MPFRNumber(XType x,unsigned int precision=ExtraPrecision<float>::VALUE,RoundingMode rounding=RoundingMode::Nearest)139   explicit MPFRNumber(XType x,
140                       unsigned int precision = ExtraPrecision<float>::VALUE,
141                       RoundingMode rounding = RoundingMode::Nearest)
142       : mpfr_precision(precision),
143         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
144     mpfr_init2(value, mpfr_precision);
145     mpfr_set_sj(value, x, mpfr_rounding);
146   }
147 
MPFRNumber(const MPFRNumber & other)148   MPFRNumber(const MPFRNumber &other)
149       : mpfr_precision(other.mpfr_precision),
150         mpfr_rounding(other.mpfr_rounding) {
151     mpfr_init2(value, mpfr_precision);
152     mpfr_set(value, other.value, mpfr_rounding);
153   }
154 
MPFRNumber(const MPFRNumber & other,unsigned int precision)155   MPFRNumber(const MPFRNumber &other, unsigned int precision)
156       : mpfr_precision(precision), mpfr_rounding(other.mpfr_rounding) {
157     mpfr_init2(value, mpfr_precision);
158     mpfr_set(value, other.value, mpfr_rounding);
159   }
160 
~MPFRNumber()161   ~MPFRNumber() { mpfr_clear(value); }
162 
operator =(const MPFRNumber & rhs)163   MPFRNumber &operator=(const MPFRNumber &rhs) {
164     mpfr_precision = rhs.mpfr_precision;
165     mpfr_rounding = rhs.mpfr_rounding;
166     mpfr_set(value, rhs.value, mpfr_rounding);
167     return *this;
168   }
169 
is_nan() const170   bool is_nan() const { return mpfr_nan_p(value); }
171 
abs() const172   MPFRNumber abs() const {
173     MPFRNumber result(*this);
174     mpfr_abs(result.value, value, mpfr_rounding);
175     return result;
176   }
177 
acos() const178   MPFRNumber acos() const {
179     MPFRNumber result(*this);
180     mpfr_acos(result.value, value, mpfr_rounding);
181     return result;
182   }
183 
acosh() const184   MPFRNumber acosh() const {
185     MPFRNumber result(*this);
186     mpfr_acosh(result.value, value, mpfr_rounding);
187     return result;
188   }
189 
add(const MPFRNumber & b) const190   MPFRNumber add(const MPFRNumber &b) const {
191     MPFRNumber result(*this);
192     mpfr_add(result.value, value, b.value, mpfr_rounding);
193     return result;
194   }
195 
asin() const196   MPFRNumber asin() const {
197     MPFRNumber result(*this);
198     mpfr_asin(result.value, value, mpfr_rounding);
199     return result;
200   }
201 
asinh() const202   MPFRNumber asinh() const {
203     MPFRNumber result(*this);
204     mpfr_asinh(result.value, value, mpfr_rounding);
205     return result;
206   }
207 
atan() const208   MPFRNumber atan() const {
209     MPFRNumber result(*this);
210     mpfr_atan(result.value, value, mpfr_rounding);
211     return result;
212   }
213 
atan2(const MPFRNumber & b)214   MPFRNumber atan2(const MPFRNumber &b) {
215     MPFRNumber result(*this);
216     mpfr_atan2(result.value, value, b.value, mpfr_rounding);
217     return result;
218   }
219 
atanh() const220   MPFRNumber atanh() const {
221     MPFRNumber result(*this);
222     mpfr_atanh(result.value, value, mpfr_rounding);
223     return result;
224   }
225 
cbrt() const226   MPFRNumber cbrt() const {
227     MPFRNumber result(*this);
228     mpfr_cbrt(result.value, value, mpfr_rounding);
229     return result;
230   }
231 
ceil() const232   MPFRNumber ceil() const {
233     MPFRNumber result(*this);
234     mpfr_ceil(result.value, value);
235     return result;
236   }
237 
cos() const238   MPFRNumber cos() const {
239     MPFRNumber result(*this);
240     mpfr_cos(result.value, value, mpfr_rounding);
241     return result;
242   }
243 
cosh() const244   MPFRNumber cosh() const {
245     MPFRNumber result(*this);
246     mpfr_cosh(result.value, value, mpfr_rounding);
247     return result;
248   }
249 
cospi() const250   MPFRNumber cospi() const {
251     MPFRNumber result(*this);
252 
253 #if MPFR_VERSION_MAJOR > 4 ||                                                  \
254     (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2)
255     mpfr_cospi(result.value, value, mpfr_rounding);
256     return result;
257 #else
258     if (mpfr_integer_p(value)) {
259       mpz_t integer;
260       mpz_init(integer);
261       mpfr_get_z(integer, value, mpfr_rounding);
262 
263       int d = mpz_tstbit(integer, 0);
264       mpfr_set_si(result.value, d ? -1 : 1, mpfr_rounding);
265       mpz_clear(integer);
266       return result;
267     }
268 
269     MPFRNumber value_pi(0.0, 1280);
270     mpfr_const_pi(value_pi.value, MPFR_RNDN);
271     mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
272     mpfr_cos(result.value, value_pi.value, mpfr_rounding);
273 
274     return result;
275 #endif
276   }
277 
erf() const278   MPFRNumber erf() const {
279     MPFRNumber result(*this);
280     mpfr_erf(result.value, value, mpfr_rounding);
281     return result;
282   }
283 
exp() const284   MPFRNumber exp() const {
285     MPFRNumber result(*this);
286     mpfr_exp(result.value, value, mpfr_rounding);
287     return result;
288   }
289 
exp2() const290   MPFRNumber exp2() const {
291     MPFRNumber result(*this);
292     mpfr_exp2(result.value, value, mpfr_rounding);
293     return result;
294   }
295 
exp2m1() const296   MPFRNumber exp2m1() const {
297     // TODO: Only use mpfr_exp2m1 once CI and buildbots get MPFR >= 4.2.0.
298 #if MPFR_VERSION_MAJOR > 4 ||                                                  \
299     (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2)
300     MPFRNumber result(*this);
301     mpfr_exp2m1(result.value, value, mpfr_rounding);
302     return result;
303 #else
304     unsigned int prec = mpfr_precision * 3;
305     MPFRNumber result(*this, prec);
306 
307     float f = mpfr_get_flt(abs().value, mpfr_rounding);
308     if (f > 0.5f && f < 0x1.0p30f) {
309       mpfr_exp2(result.value, value, mpfr_rounding);
310       mpfr_sub_ui(result.value, result.value, 1, mpfr_rounding);
311       return result;
312     }
313 
314     MPFRNumber ln2(2.0f, prec);
315     // log(2)
316     mpfr_log(ln2.value, ln2.value, mpfr_rounding);
317     // x * log(2)
318     mpfr_mul(result.value, value, ln2.value, mpfr_rounding);
319     // e^(x * log(2)) - 1
320     int ex = mpfr_expm1(result.value, result.value, mpfr_rounding);
321     mpfr_subnormalize(result.value, ex, mpfr_rounding);
322     return result;
323 #endif
324   }
325 
exp10() const326   MPFRNumber exp10() const {
327     MPFRNumber result(*this);
328     mpfr_exp10(result.value, value, mpfr_rounding);
329     return result;
330   }
331 
exp10m1() const332   MPFRNumber exp10m1() const {
333     // TODO: Only use mpfr_exp10m1 once CI and buildbots get MPFR >= 4.2.0.
334 #if MPFR_VERSION_MAJOR > 4 ||                                                  \
335     (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2)
336     MPFRNumber result(*this);
337     mpfr_exp10m1(result.value, value, mpfr_rounding);
338     return result;
339 #else
340     unsigned int prec = mpfr_precision * 3;
341     MPFRNumber result(*this, prec);
342 
343     MPFRNumber ln10(10.0f, prec);
344     // log(10)
345     mpfr_log(ln10.value, ln10.value, mpfr_rounding);
346     // x * log(10)
347     mpfr_mul(result.value, value, ln10.value, mpfr_rounding);
348     // e^(x * log(10)) - 1
349     int ex = mpfr_expm1(result.value, result.value, mpfr_rounding);
350     mpfr_subnormalize(result.value, ex, mpfr_rounding);
351     return result;
352 #endif
353   }
354 
expm1() const355   MPFRNumber expm1() const {
356     MPFRNumber result(*this);
357     mpfr_expm1(result.value, value, mpfr_rounding);
358     return result;
359   }
360 
div(const MPFRNumber & b) const361   MPFRNumber div(const MPFRNumber &b) const {
362     MPFRNumber result(*this);
363     mpfr_div(result.value, value, b.value, mpfr_rounding);
364     return result;
365   }
366 
floor() const367   MPFRNumber floor() const {
368     MPFRNumber result(*this);
369     mpfr_floor(result.value, value);
370     return result;
371   }
372 
fmod(const MPFRNumber & b)373   MPFRNumber fmod(const MPFRNumber &b) {
374     MPFRNumber result(*this);
375     mpfr_fmod(result.value, value, b.value, mpfr_rounding);
376     return result;
377   }
378 
frexp(int & exp)379   MPFRNumber frexp(int &exp) {
380     MPFRNumber result(*this);
381     mpfr_exp_t resultExp;
382     mpfr_frexp(&resultExp, result.value, value, mpfr_rounding);
383     exp = resultExp;
384     return result;
385   }
386 
hypot(const MPFRNumber & b)387   MPFRNumber hypot(const MPFRNumber &b) {
388     MPFRNumber result(*this);
389     mpfr_hypot(result.value, value, b.value, mpfr_rounding);
390     return result;
391   }
392 
log() const393   MPFRNumber log() const {
394     MPFRNumber result(*this);
395     mpfr_log(result.value, value, mpfr_rounding);
396     return result;
397   }
398 
log2() const399   MPFRNumber log2() const {
400     MPFRNumber result(*this);
401     mpfr_log2(result.value, value, mpfr_rounding);
402     return result;
403   }
404 
log10() const405   MPFRNumber log10() const {
406     MPFRNumber result(*this);
407     mpfr_log10(result.value, value, mpfr_rounding);
408     return result;
409   }
410 
log1p() const411   MPFRNumber log1p() const {
412     MPFRNumber result(*this);
413     mpfr_log1p(result.value, value, mpfr_rounding);
414     return result;
415   }
416 
pow(const MPFRNumber & b)417   MPFRNumber pow(const MPFRNumber &b) {
418     MPFRNumber result(*this);
419     mpfr_pow(result.value, value, b.value, mpfr_rounding);
420     return result;
421   }
422 
remquo(const MPFRNumber & divisor,int & quotient)423   MPFRNumber remquo(const MPFRNumber &divisor, int &quotient) {
424     MPFRNumber remainder(*this);
425     long q;
426     mpfr_remquo(remainder.value, &q, value, divisor.value, mpfr_rounding);
427     quotient = q;
428     return remainder;
429   }
430 
round() const431   MPFRNumber round() const {
432     MPFRNumber result(*this);
433     mpfr_round(result.value, value);
434     return result;
435   }
436 
roundeven() const437   MPFRNumber roundeven() const {
438     MPFRNumber result(*this);
439 #if MPFR_VERSION_MAJOR >= 4
440     mpfr_roundeven(result.value, value);
441 #else
442     mpfr_rint(result.value, value, MPFR_RNDN);
443 #endif
444     return result;
445   }
446 
round_to_long(long & result) const447   bool round_to_long(long &result) const {
448     // We first calculate the rounded value. This way, when converting
449     // to long using mpfr_get_si, the rounding direction of MPFR_RNDN
450     // (or any other rounding mode), does not have an influence.
451     MPFRNumber roundedValue = round();
452     mpfr_clear_erangeflag();
453     result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
454     return mpfr_erangeflag_p();
455   }
456 
round_to_long(mpfr_rnd_t rnd,long & result) const457   bool round_to_long(mpfr_rnd_t rnd, long &result) const {
458     MPFRNumber rint_result(*this);
459     mpfr_rint(rint_result.value, value, rnd);
460     return rint_result.round_to_long(result);
461   }
462 
rint(mpfr_rnd_t rnd) const463   MPFRNumber rint(mpfr_rnd_t rnd) const {
464     MPFRNumber result(*this);
465     mpfr_rint(result.value, value, rnd);
466     return result;
467   }
468 
mod_2pi() const469   MPFRNumber mod_2pi() const {
470     MPFRNumber result(0.0, 1280);
471     MPFRNumber _2pi(0.0, 1280);
472     mpfr_const_pi(_2pi.value, MPFR_RNDN);
473     mpfr_mul_si(_2pi.value, _2pi.value, 2, MPFR_RNDN);
474     mpfr_fmod(result.value, value, _2pi.value, MPFR_RNDN);
475     return result;
476   }
477 
mod_pi_over_2() const478   MPFRNumber mod_pi_over_2() const {
479     MPFRNumber result(0.0, 1280);
480     MPFRNumber pi_over_2(0.0, 1280);
481     mpfr_const_pi(pi_over_2.value, MPFR_RNDN);
482     mpfr_mul_d(pi_over_2.value, pi_over_2.value, 0.5, MPFR_RNDN);
483     mpfr_fmod(result.value, value, pi_over_2.value, MPFR_RNDN);
484     return result;
485   }
486 
mod_pi_over_4() const487   MPFRNumber mod_pi_over_4() const {
488     MPFRNumber result(0.0, 1280);
489     MPFRNumber pi_over_4(0.0, 1280);
490     mpfr_const_pi(pi_over_4.value, MPFR_RNDN);
491     mpfr_mul_d(pi_over_4.value, pi_over_4.value, 0.25, MPFR_RNDN);
492     mpfr_fmod(result.value, value, pi_over_4.value, MPFR_RNDN);
493     return result;
494   }
495 
sin() const496   MPFRNumber sin() const {
497     MPFRNumber result(*this);
498     mpfr_sin(result.value, value, mpfr_rounding);
499     return result;
500   }
501 
sinpi() const502   MPFRNumber sinpi() const {
503     MPFRNumber result(*this);
504 
505 #if MPFR_VERSION_MAJOR > 4 ||                                                  \
506     (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2)
507 
508     mpfr_sinpi(result.value, value, mpfr_rounding);
509     return result;
510 #else
511     if (mpfr_integer_p(value)) {
512       mpfr_set_si(result.value, 0, mpfr_rounding);
513       return result;
514     }
515 
516     MPFRNumber value_mul_two(*this);
517     mpfr_mul_si(value_mul_two.value, value, 2, MPFR_RNDN);
518 
519     if (mpfr_integer_p(value_mul_two.value)) {
520       auto d = mpfr_get_si(value, MPFR_RNDD);
521       mpfr_set_si(result.value, (d & 1) ? -1 : 1, mpfr_rounding);
522       return result;
523     }
524 
525     MPFRNumber value_pi(0.0, 1280);
526     mpfr_const_pi(value_pi.value, MPFR_RNDN);
527     mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
528     mpfr_sin(result.value, value_pi.value, mpfr_rounding);
529     return result;
530 #endif
531   }
532 
sinh() const533   MPFRNumber sinh() const {
534     MPFRNumber result(*this);
535     mpfr_sinh(result.value, value, mpfr_rounding);
536     return result;
537   }
538 
sqrt() const539   MPFRNumber sqrt() const {
540     MPFRNumber result(*this);
541     mpfr_sqrt(result.value, value, mpfr_rounding);
542     return result;
543   }
544 
sub(const MPFRNumber & b) const545   MPFRNumber sub(const MPFRNumber &b) const {
546     MPFRNumber result(*this);
547     mpfr_sub(result.value, value, b.value, mpfr_rounding);
548     return result;
549   }
550 
tan() const551   MPFRNumber tan() const {
552     MPFRNumber result(*this);
553     mpfr_tan(result.value, value, mpfr_rounding);
554     return result;
555   }
556 
tanh() const557   MPFRNumber tanh() const {
558     MPFRNumber result(*this);
559     mpfr_tanh(result.value, value, mpfr_rounding);
560     return result;
561   }
562 
tanpi() const563   MPFRNumber tanpi() const {
564     MPFRNumber result(*this);
565 
566 #if MPFR_VERSION_MAJOR > 4 ||                                                  \
567     (MPFR_VERSION_MAJOR == 4 && MPFR_VERSION_MINOR >= 2)
568 
569     mpfr_tanpi(result.value, value, mpfr_rounding);
570     return result;
571 #else
572     MPFRNumber value_ret_exact(*this);
573     MPFRNumber value_one(*this);
574     mpfr_set_si(value_one.value, 1, MPFR_RNDN);
575     mpfr_fmod(value_ret_exact.value, value, value_one.value, mpfr_rounding);
576     mpfr_mul_si(value_ret_exact.value, value_ret_exact.value, 4, MPFR_RNDN);
577 
578     if (mpfr_integer_p(value_ret_exact.value)) {
579       int mod = mpfr_get_si(value_ret_exact.value, MPFR_RNDN);
580       mod = (mod < 0 ? -1 * mod : mod);
581 
582       switch (mod) {
583       case 0:
584         mpfr_set_si(result.value, 0, mpfr_rounding);
585         break;
586       case 1:
587         mpfr_set_si(result.value, (mpfr_signbit(value) ? -1 : 1),
588                     mpfr_rounding);
589         break;
590       case 2: {
591         auto d = mpfr_get_si(value, MPFR_RNDZ);
592         d += mpfr_sgn(value) > 0 ? 0 : 1;
593         mpfr_set_inf(result.value, (d & 1) ? -1 : 1);
594         break;
595       }
596       case 3:
597         mpfr_set_si(result.value, (mpfr_signbit(value) ? 1 : -1),
598                     mpfr_rounding);
599         break;
600       }
601 
602       return result;
603     }
604 
605     MPFRNumber value_pi(0.0, 1280);
606     mpfr_const_pi(value_pi.value, MPFR_RNDN);
607     mpfr_mul(value_pi.value, value_pi.value, value, MPFR_RNDN);
608     mpfr_tan(result.value, value_pi.value, mpfr_rounding);
609     return result;
610 #endif
611   }
612 
trunc() const613   MPFRNumber trunc() const {
614     MPFRNumber result(*this);
615     mpfr_trunc(result.value, value);
616     return result;
617   }
618 
fma(const MPFRNumber & b,const MPFRNumber & c)619   MPFRNumber fma(const MPFRNumber &b, const MPFRNumber &c) {
620     MPFRNumber result(*this);
621     mpfr_fma(result.value, value, b.value, c.value, mpfr_rounding);
622     return result;
623   }
624 
mul(const MPFRNumber & b)625   MPFRNumber mul(const MPFRNumber &b) {
626     MPFRNumber result(*this);
627     mpfr_mul(result.value, value, b.value, mpfr_rounding);
628     return result;
629   }
630 
str() const631   cpp::string str() const {
632     // 200 bytes should be more than sufficient to hold a 100-digit number
633     // plus additional bytes for the decimal point, '-' sign etc.
634     constexpr size_t printBufSize = 200;
635     char buffer[printBufSize];
636     mpfr_snprintf(buffer, printBufSize, "%100.50Rf", value);
637     cpp::string_view view(buffer);
638     // Trim whitespaces
639     const char whitespace = ' ';
640     while (!view.empty() && view.front() == whitespace)
641       view.remove_prefix(1);
642     while (!view.empty() && view.back() == whitespace)
643       view.remove_suffix(1);
644     return cpp::string(view.data());
645   }
646 
647   // These functions are useful for debugging.
648   template <typename T> T as() const;
649 
dump(const char * msg) const650   void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
651 
652   // Return the ULP (units-in-the-last-place) difference between the
653   // stored MPFR and a floating point number.
654   //
655   // We define ULP difference as follows:
656   //   If exponents of this value and the |input| are same, then:
657   //     ULP(this_value, input) = abs(this_value - input) / eps(input)
658   //   else:
659   //     max = max(abs(this_value), abs(input))
660   //     min = min(abs(this_value), abs(input))
661   //     maxExponent = exponent(max)
662   //     ULP(this_value, input) = (max - 2^maxExponent) / eps(max) +
663   //                              (2^maxExponent - min) / eps(min)
664   //
665   // Remarks:
666   // 1. A ULP of 0.0 will imply that the value is correctly rounded.
667   // 2. We expect that this value and the value to be compared (the [input]
668   //    argument) are reasonable close, and we will provide an upper bound
669   //    of ULP value for testing.  Morever, most of the fractional parts of
670   //    ULP value do not matter much, so using double as the return type
671   //    should be good enough.
672   // 3. For close enough values (values which don't diff in their exponent by
673   //    not more than 1), a ULP difference of N indicates a bit distance
674   //    of N between this number and [input].
675   // 4. A values of +0.0 and -0.0 are treated as equal.
676   template <typename T>
677   cpp::enable_if_t<cpp::is_floating_point_v<T>, MPFRNumber>
ulp_as_mpfr_number(T input)678   ulp_as_mpfr_number(T input) {
679     T thisAsT = as<T>();
680     if (thisAsT == input)
681       return MPFRNumber(0.0);
682 
683     if (is_nan()) {
684       if (FPBits<T>(input).is_nan())
685         return MPFRNumber(0.0);
686       return MPFRNumber(FPBits<T>::inf().get_val());
687     }
688 
689     int thisExponent = FPBits<T>(thisAsT).get_exponent();
690     int inputExponent = FPBits<T>(input).get_exponent();
691     // Adjust the exponents for denormal numbers.
692     if (FPBits<T>(thisAsT).is_subnormal())
693       ++thisExponent;
694     if (FPBits<T>(input).is_subnormal())
695       ++inputExponent;
696 
697     if (thisAsT * input < 0 || thisExponent == inputExponent) {
698       MPFRNumber inputMPFR(input);
699       mpfr_sub(inputMPFR.value, value, inputMPFR.value, MPFR_RNDN);
700       mpfr_abs(inputMPFR.value, inputMPFR.value, MPFR_RNDN);
701       mpfr_mul_2si(inputMPFR.value, inputMPFR.value,
702                    -thisExponent + FPBits<T>::FRACTION_LEN, MPFR_RNDN);
703       return inputMPFR;
704     }
705 
706     // If the control reaches here, it means that this number and input are
707     // of the same sign but different exponent. In such a case, ULP error is
708     // calculated as sum of two parts.
709     thisAsT = FPBits<T>(thisAsT).abs().get_val();
710     input = FPBits<T>(input).abs().get_val();
711     T min = thisAsT > input ? input : thisAsT;
712     T max = thisAsT > input ? thisAsT : input;
713     int minExponent = FPBits<T>(min).get_exponent();
714     int maxExponent = FPBits<T>(max).get_exponent();
715     // Adjust the exponents for denormal numbers.
716     if (FPBits<T>(min).is_subnormal())
717       ++minExponent;
718     if (FPBits<T>(max).is_subnormal())
719       ++maxExponent;
720 
721     MPFRNumber minMPFR(min);
722     MPFRNumber maxMPFR(max);
723 
724     MPFRNumber pivot(uint32_t(1));
725     mpfr_mul_2si(pivot.value, pivot.value, maxExponent, MPFR_RNDN);
726 
727     mpfr_sub(minMPFR.value, pivot.value, minMPFR.value, MPFR_RNDN);
728     mpfr_mul_2si(minMPFR.value, minMPFR.value,
729                  -minExponent + FPBits<T>::FRACTION_LEN, MPFR_RNDN);
730 
731     mpfr_sub(maxMPFR.value, maxMPFR.value, pivot.value, MPFR_RNDN);
732     mpfr_mul_2si(maxMPFR.value, maxMPFR.value,
733                  -maxExponent + FPBits<T>::FRACTION_LEN, MPFR_RNDN);
734 
735     mpfr_add(minMPFR.value, minMPFR.value, maxMPFR.value, MPFR_RNDN);
736     return minMPFR;
737   }
738 
739   template <typename T>
740   cpp::enable_if_t<cpp::is_floating_point_v<T>, cpp::string>
ulp_as_string(T input)741   ulp_as_string(T input) {
742     MPFRNumber num = ulp_as_mpfr_number(input);
743     return num.str();
744   }
745 
746   template <typename T>
ulp(T input)747   cpp::enable_if_t<cpp::is_floating_point_v<T>, double> ulp(T input) {
748     MPFRNumber num = ulp_as_mpfr_number(input);
749     return num.as<double>();
750   }
751 };
752 
as() const753 template <> float MPFRNumber::as<float>() const {
754   return mpfr_get_flt(value, mpfr_rounding);
755 }
756 
as() const757 template <> double MPFRNumber::as<double>() const {
758   return mpfr_get_d(value, mpfr_rounding);
759 }
760 
as() const761 template <> long double MPFRNumber::as<long double>() const {
762   return mpfr_get_ld(value, mpfr_rounding);
763 }
764 
765 #ifdef LIBC_TYPES_HAS_FLOAT16
as() const766 template <> float16 MPFRNumber::as<float16>() const {
767   // TODO: Either prove that this cast won't cause double-rounding errors, or
768   // find a better way to get a float16.
769   return fputil::cast<float16>(mpfr_get_d(value, mpfr_rounding));
770 }
771 #endif
772 
773 namespace internal {
774 
775 template <typename InputType>
776 cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
unary_operation(Operation op,InputType input,unsigned int precision,RoundingMode rounding)777 unary_operation(Operation op, InputType input, unsigned int precision,
778                 RoundingMode rounding) {
779   MPFRNumber mpfrInput(input, precision, rounding);
780   switch (op) {
781   case Operation::Abs:
782     return mpfrInput.abs();
783   case Operation::Acos:
784     return mpfrInput.acos();
785   case Operation::Acosh:
786     return mpfrInput.acosh();
787   case Operation::Asin:
788     return mpfrInput.asin();
789   case Operation::Asinh:
790     return mpfrInput.asinh();
791   case Operation::Atan:
792     return mpfrInput.atan();
793   case Operation::Atanh:
794     return mpfrInput.atanh();
795   case Operation::Cbrt:
796     return mpfrInput.cbrt();
797   case Operation::Ceil:
798     return mpfrInput.ceil();
799   case Operation::Cos:
800     return mpfrInput.cos();
801   case Operation::Cosh:
802     return mpfrInput.cosh();
803   case Operation::Cospi:
804     return mpfrInput.cospi();
805   case Operation::Erf:
806     return mpfrInput.erf();
807   case Operation::Exp:
808     return mpfrInput.exp();
809   case Operation::Exp2:
810     return mpfrInput.exp2();
811   case Operation::Exp2m1:
812     return mpfrInput.exp2m1();
813   case Operation::Exp10:
814     return mpfrInput.exp10();
815   case Operation::Exp10m1:
816     return mpfrInput.exp10m1();
817   case Operation::Expm1:
818     return mpfrInput.expm1();
819   case Operation::Floor:
820     return mpfrInput.floor();
821   case Operation::Log:
822     return mpfrInput.log();
823   case Operation::Log2:
824     return mpfrInput.log2();
825   case Operation::Log10:
826     return mpfrInput.log10();
827   case Operation::Log1p:
828     return mpfrInput.log1p();
829   case Operation::Mod2PI:
830     return mpfrInput.mod_2pi();
831   case Operation::ModPIOver2:
832     return mpfrInput.mod_pi_over_2();
833   case Operation::ModPIOver4:
834     return mpfrInput.mod_pi_over_4();
835   case Operation::Round:
836     return mpfrInput.round();
837   case Operation::RoundEven:
838     return mpfrInput.roundeven();
839   case Operation::Sin:
840     return mpfrInput.sin();
841   case Operation::Sinpi:
842     return mpfrInput.sinpi();
843   case Operation::Sinh:
844     return mpfrInput.sinh();
845   case Operation::Sqrt:
846     return mpfrInput.sqrt();
847   case Operation::Tan:
848     return mpfrInput.tan();
849   case Operation::Tanh:
850     return mpfrInput.tanh();
851   case Operation::Tanpi:
852     return mpfrInput.tanpi();
853   case Operation::Trunc:
854     return mpfrInput.trunc();
855   default:
856     __builtin_unreachable();
857   }
858 }
859 
860 template <typename InputType>
861 cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
unary_operation_two_outputs(Operation op,InputType input,int & output,unsigned int precision,RoundingMode rounding)862 unary_operation_two_outputs(Operation op, InputType input, int &output,
863                             unsigned int precision, RoundingMode rounding) {
864   MPFRNumber mpfrInput(input, precision, rounding);
865   switch (op) {
866   case Operation::Frexp:
867     return mpfrInput.frexp(output);
868   default:
869     __builtin_unreachable();
870   }
871 }
872 
873 template <typename InputType>
874 cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
binary_operation_one_output(Operation op,InputType x,InputType y,unsigned int precision,RoundingMode rounding)875 binary_operation_one_output(Operation op, InputType x, InputType y,
876                             unsigned int precision, RoundingMode rounding) {
877   MPFRNumber inputX(x, precision, rounding);
878   MPFRNumber inputY(y, precision, rounding);
879   switch (op) {
880   case Operation::Add:
881     return inputX.add(inputY);
882   case Operation::Atan2:
883     return inputX.atan2(inputY);
884   case Operation::Div:
885     return inputX.div(inputY);
886   case Operation::Fmod:
887     return inputX.fmod(inputY);
888   case Operation::Hypot:
889     return inputX.hypot(inputY);
890   case Operation::Mul:
891     return inputX.mul(inputY);
892   case Operation::Pow:
893     return inputX.pow(inputY);
894   case Operation::Sub:
895     return inputX.sub(inputY);
896   default:
897     __builtin_unreachable();
898   }
899 }
900 
901 template <typename InputType>
902 cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
binary_operation_two_outputs(Operation op,InputType x,InputType y,int & output,unsigned int precision,RoundingMode rounding)903 binary_operation_two_outputs(Operation op, InputType x, InputType y,
904                              int &output, unsigned int precision,
905                              RoundingMode rounding) {
906   MPFRNumber inputX(x, precision, rounding);
907   MPFRNumber inputY(y, precision, rounding);
908   switch (op) {
909   case Operation::RemQuo:
910     return inputX.remquo(inputY, output);
911   default:
912     __builtin_unreachable();
913   }
914 }
915 
916 template <typename InputType>
917 cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
ternary_operation_one_output(Operation op,InputType x,InputType y,InputType z,unsigned int precision,RoundingMode rounding)918 ternary_operation_one_output(Operation op, InputType x, InputType y,
919                              InputType z, unsigned int precision,
920                              RoundingMode rounding) {
921   // For FMA function, we just need to compare with the mpfr_fma with the same
922   // precision as InputType.  Using higher precision as the intermediate results
923   // to compare might incorrectly fail due to double-rounding errors.
924   MPFRNumber inputX(x, precision, rounding);
925   MPFRNumber inputY(y, precision, rounding);
926   MPFRNumber inputZ(z, precision, rounding);
927   switch (op) {
928   case Operation::Fma:
929     return inputX.fma(inputY, inputZ);
930   default:
931     __builtin_unreachable();
932   }
933 }
934 
935 // Remark: For all the explain_*_error functions, we will use std::stringstream
936 // to build the complete error messages before sending it to the outstream `OS`
937 // once at the end.  This will stop the error messages from interleaving when
938 // the tests are running concurrently.
939 template <typename InputType, typename OutputType>
explain_unary_operation_single_output_error(Operation op,InputType input,OutputType matchValue,double ulp_tolerance,RoundingMode rounding)940 void explain_unary_operation_single_output_error(Operation op, InputType input,
941                                                  OutputType matchValue,
942                                                  double ulp_tolerance,
943                                                  RoundingMode rounding) {
944   unsigned int precision = get_precision<InputType>(ulp_tolerance);
945   MPFRNumber mpfrInput(input, precision);
946   MPFRNumber mpfr_result;
947   mpfr_result = unary_operation(op, input, precision, rounding);
948   MPFRNumber mpfrMatchValue(matchValue);
949   cpp::array<char, 1024> msg_buf;
950   cpp::StringStream msg(msg_buf);
951   msg << "Match value not within tolerance value of MPFR result:\n"
952       << "  Input decimal: " << mpfrInput.str() << '\n';
953   msg << "     Input bits: " << str(FPBits<InputType>(input)) << '\n';
954   msg << '\n' << "  Match decimal: " << mpfrMatchValue.str() << '\n';
955   msg << "     Match bits: " << str(FPBits<OutputType>(matchValue)) << '\n';
956   msg << '\n' << "    MPFR result: " << mpfr_result.str() << '\n';
957   msg << "   MPFR rounded: "
958       << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
959   msg << '\n';
960   msg << "      ULP error: " << mpfr_result.ulp_as_mpfr_number(matchValue).str()
961       << '\n';
962   if (msg.overflow())
963     __builtin_unreachable();
964   tlog << msg.str();
965 }
966 
967 template void explain_unary_operation_single_output_error(Operation op, float,
968                                                           float, double,
969                                                           RoundingMode);
970 template void explain_unary_operation_single_output_error(Operation op, double,
971                                                           double, double,
972                                                           RoundingMode);
973 template void explain_unary_operation_single_output_error(Operation op,
974                                                           long double,
975                                                           long double, double,
976                                                           RoundingMode);
977 template void explain_unary_operation_single_output_error(Operation op, double,
978                                                           float, double,
979                                                           RoundingMode);
980 template void explain_unary_operation_single_output_error(Operation op,
981                                                           long double, float,
982                                                           double, RoundingMode);
983 template void explain_unary_operation_single_output_error(Operation op,
984                                                           long double, double,
985                                                           double, RoundingMode);
986 
987 #ifdef LIBC_TYPES_HAS_FLOAT16
988 template void explain_unary_operation_single_output_error(Operation op, float16,
989                                                           float16, double,
990                                                           RoundingMode);
991 template void explain_unary_operation_single_output_error(Operation op, float,
992                                                           float16, double,
993                                                           RoundingMode);
994 template void explain_unary_operation_single_output_error(Operation op, double,
995                                                           float16, double,
996                                                           RoundingMode);
997 template void explain_unary_operation_single_output_error(Operation op,
998                                                           long double, float16,
999                                                           double, RoundingMode);
1000 #endif
1001 
1002 template <typename T>
explain_unary_operation_two_outputs_error(Operation op,T input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding)1003 void explain_unary_operation_two_outputs_error(
1004     Operation op, T input, const BinaryOutput<T> &libc_result,
1005     double ulp_tolerance, RoundingMode rounding) {
1006   unsigned int precision = get_precision<T>(ulp_tolerance);
1007   MPFRNumber mpfrInput(input, precision);
1008   int mpfrIntResult;
1009   MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
1010                                                        precision, rounding);
1011 
1012   if (mpfrIntResult != libc_result.i) {
1013     tlog << "MPFR integral result: " << mpfrIntResult << '\n'
1014          << "Libc integral result: " << libc_result.i << '\n';
1015   } else {
1016     tlog << "Integral result from libc matches integral result from MPFR.\n";
1017   }
1018 
1019   MPFRNumber mpfrMatchValue(libc_result.f);
1020   tlog
1021       << "Libc floating point result is not within tolerance value of the MPFR "
1022       << "result.\n\n";
1023 
1024   tlog << "            Input decimal: " << mpfrInput.str() << "\n\n";
1025 
1026   tlog << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
1027   tlog << " Libc floating point bits: " << str(FPBits<T>(libc_result.f))
1028        << '\n';
1029   tlog << "\n\n";
1030 
1031   tlog << "              MPFR result: " << mpfr_result.str() << '\n';
1032   tlog << "             MPFR rounded: " << str(FPBits<T>(mpfr_result.as<T>()))
1033        << '\n';
1034   tlog << '\n'
1035        << "                ULP error: "
1036        << mpfr_result.ulp_as_mpfr_number(libc_result.f).str() << '\n';
1037 }
1038 
1039 template void explain_unary_operation_two_outputs_error<float>(
1040     Operation, float, const BinaryOutput<float> &, double, RoundingMode);
1041 template void explain_unary_operation_two_outputs_error<double>(
1042     Operation, double, const BinaryOutput<double> &, double, RoundingMode);
1043 template void explain_unary_operation_two_outputs_error<long double>(
1044     Operation, long double, const BinaryOutput<long double> &, double,
1045     RoundingMode);
1046 
1047 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)1048 void explain_binary_operation_two_outputs_error(
1049     Operation op, const BinaryInput<T> &input,
1050     const BinaryOutput<T> &libc_result, double ulp_tolerance,
1051     RoundingMode rounding) {
1052   unsigned int precision = get_precision<T>(ulp_tolerance);
1053   MPFRNumber mpfrX(input.x, precision);
1054   MPFRNumber mpfrY(input.y, precision);
1055   int mpfrIntResult;
1056   MPFRNumber mpfr_result = binary_operation_two_outputs(
1057       op, input.x, input.y, mpfrIntResult, precision, rounding);
1058   MPFRNumber mpfrMatchValue(libc_result.f);
1059 
1060   tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
1061        << "MPFR integral result: " << mpfrIntResult << '\n'
1062        << "Libc integral result: " << libc_result.i << '\n'
1063        << "Libc floating point result: " << mpfrMatchValue.str() << '\n'
1064        << "               MPFR result: " << mpfr_result.str() << '\n';
1065   tlog << "Libc floating point result bits: " << str(FPBits<T>(libc_result.f))
1066        << '\n';
1067   tlog << "              MPFR rounded bits: "
1068        << str(FPBits<T>(mpfr_result.as<T>())) << '\n';
1069   tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result.f).str()
1070        << '\n';
1071 }
1072 
1073 template void explain_binary_operation_two_outputs_error<float>(
1074     Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
1075     RoundingMode);
1076 template void explain_binary_operation_two_outputs_error<double>(
1077     Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
1078     double, RoundingMode);
1079 template void explain_binary_operation_two_outputs_error<long double>(
1080     Operation, const BinaryInput<long double> &,
1081     const BinaryOutput<long double> &, double, RoundingMode);
1082 
1083 template <typename InputType, typename OutputType>
explain_binary_operation_one_output_error(Operation op,const BinaryInput<InputType> & input,OutputType libc_result,double ulp_tolerance,RoundingMode rounding)1084 void explain_binary_operation_one_output_error(
1085     Operation op, const BinaryInput<InputType> &input, OutputType libc_result,
1086     double ulp_tolerance, RoundingMode rounding) {
1087   unsigned int precision = get_precision<InputType>(ulp_tolerance);
1088   MPFRNumber mpfrX(input.x, precision);
1089   MPFRNumber mpfrY(input.y, precision);
1090   FPBits<InputType> xbits(input.x);
1091   FPBits<InputType> ybits(input.y);
1092   MPFRNumber mpfr_result =
1093       binary_operation_one_output(op, input.x, input.y, precision, rounding);
1094   MPFRNumber mpfrMatchValue(libc_result);
1095 
1096   tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
1097   tlog << "First input bits: " << str(FPBits<InputType>(input.x)) << '\n';
1098   tlog << "Second input bits: " << str(FPBits<InputType>(input.y)) << '\n';
1099 
1100   tlog << "Libc result: " << mpfrMatchValue.str() << '\n'
1101        << "MPFR result: " << mpfr_result.str() << '\n';
1102   tlog << "Libc floating point result bits: "
1103        << str(FPBits<OutputType>(libc_result)) << '\n';
1104   tlog << "              MPFR rounded bits: "
1105        << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
1106   tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str()
1107        << '\n';
1108 }
1109 
1110 template void
1111 explain_binary_operation_one_output_error(Operation, const BinaryInput<float> &,
1112                                           float, double, RoundingMode);
1113 template void explain_binary_operation_one_output_error(
1114     Operation, const BinaryInput<double> &, float, double, RoundingMode);
1115 template void explain_binary_operation_one_output_error(
1116     Operation, const BinaryInput<double> &, double, double, RoundingMode);
1117 template void explain_binary_operation_one_output_error(
1118     Operation, const BinaryInput<long double> &, float, double, RoundingMode);
1119 template void explain_binary_operation_one_output_error(
1120     Operation, const BinaryInput<long double> &, double, double, RoundingMode);
1121 template void
1122 explain_binary_operation_one_output_error(Operation,
1123                                           const BinaryInput<long double> &,
1124                                           long double, double, RoundingMode);
1125 #ifdef LIBC_TYPES_HAS_FLOAT16
1126 template void explain_binary_operation_one_output_error(
1127     Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
1128 template void
1129 explain_binary_operation_one_output_error(Operation, const BinaryInput<float> &,
1130                                           float16, double, RoundingMode);
1131 template void explain_binary_operation_one_output_error(
1132     Operation, const BinaryInput<double> &, float16, double, RoundingMode);
1133 template void explain_binary_operation_one_output_error(
1134     Operation, const BinaryInput<long double> &, float16, double, RoundingMode);
1135 #endif
1136 
1137 template <typename InputType, typename OutputType>
explain_ternary_operation_one_output_error(Operation op,const TernaryInput<InputType> & input,OutputType libc_result,double ulp_tolerance,RoundingMode rounding)1138 void explain_ternary_operation_one_output_error(
1139     Operation op, const TernaryInput<InputType> &input, OutputType libc_result,
1140     double ulp_tolerance, RoundingMode rounding) {
1141   unsigned int precision = get_precision<InputType>(ulp_tolerance);
1142   MPFRNumber mpfrX(input.x, precision);
1143   MPFRNumber mpfrY(input.y, precision);
1144   MPFRNumber mpfrZ(input.z, precision);
1145   FPBits<InputType> xbits(input.x);
1146   FPBits<InputType> ybits(input.y);
1147   FPBits<InputType> zbits(input.z);
1148   MPFRNumber mpfr_result = ternary_operation_one_output(
1149       op, input.x, input.y, input.z, precision, rounding);
1150   MPFRNumber mpfrMatchValue(libc_result);
1151 
1152   tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
1153        << " z: " << mpfrZ.str() << '\n';
1154   tlog << " First input bits: " << str(FPBits<InputType>(input.x)) << '\n';
1155   tlog << "Second input bits: " << str(FPBits<InputType>(input.y)) << '\n';
1156   tlog << " Third input bits: " << str(FPBits<InputType>(input.z)) << '\n';
1157 
1158   tlog << "Libc result: " << mpfrMatchValue.str() << '\n'
1159        << "MPFR result: " << mpfr_result.str() << '\n';
1160   tlog << "Libc floating point result bits: "
1161        << str(FPBits<OutputType>(libc_result)) << '\n';
1162   tlog << "              MPFR rounded bits: "
1163        << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
1164   tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str()
1165        << '\n';
1166 }
1167 
1168 template void explain_ternary_operation_one_output_error(
1169     Operation, const TernaryInput<float> &, float, double, RoundingMode);
1170 template void explain_ternary_operation_one_output_error(
1171     Operation, const TernaryInput<double> &, float, double, RoundingMode);
1172 template void explain_ternary_operation_one_output_error(
1173     Operation, const TernaryInput<double> &, double, double, RoundingMode);
1174 template void explain_ternary_operation_one_output_error(
1175     Operation, const TernaryInput<long double> &, float, double, RoundingMode);
1176 template void explain_ternary_operation_one_output_error(
1177     Operation, const TernaryInput<long double> &, double, double, RoundingMode);
1178 template void
1179 explain_ternary_operation_one_output_error(Operation,
1180                                            const TernaryInput<long double> &,
1181                                            long double, double, RoundingMode);
1182 
1183 #ifdef LIBC_TYPES_HAS_FLOAT16
1184 template void explain_ternary_operation_one_output_error(
1185     Operation, const TernaryInput<float> &, float16, double, RoundingMode);
1186 template void explain_ternary_operation_one_output_error(
1187     Operation, const TernaryInput<double> &, float16, double, RoundingMode);
1188 template void
1189 explain_ternary_operation_one_output_error(Operation,
1190                                            const TernaryInput<long double> &,
1191                                            float16, double, RoundingMode);
1192 #endif
1193 
1194 template <typename InputType, typename OutputType>
compare_unary_operation_single_output(Operation op,InputType input,OutputType libc_result,double ulp_tolerance,RoundingMode rounding)1195 bool compare_unary_operation_single_output(Operation op, InputType input,
1196                                            OutputType libc_result,
1197                                            double ulp_tolerance,
1198                                            RoundingMode rounding) {
1199   unsigned int precision = get_precision<InputType>(ulp_tolerance);
1200   MPFRNumber mpfr_result;
1201   mpfr_result = unary_operation(op, input, precision, rounding);
1202   double ulp = mpfr_result.ulp(libc_result);
1203   return (ulp <= ulp_tolerance);
1204 }
1205 
1206 template bool compare_unary_operation_single_output(Operation, float, float,
1207                                                     double, RoundingMode);
1208 template bool compare_unary_operation_single_output(Operation, double, double,
1209                                                     double, RoundingMode);
1210 template bool compare_unary_operation_single_output(Operation, long double,
1211                                                     long double, double,
1212                                                     RoundingMode);
1213 template bool compare_unary_operation_single_output(Operation, double, float,
1214                                                     double, RoundingMode);
1215 template bool compare_unary_operation_single_output(Operation, long double,
1216                                                     float, double,
1217                                                     RoundingMode);
1218 template bool compare_unary_operation_single_output(Operation, long double,
1219                                                     double, double,
1220                                                     RoundingMode);
1221 #ifdef LIBC_TYPES_HAS_FLOAT16
1222 template bool compare_unary_operation_single_output(Operation, float16, float16,
1223                                                     double, RoundingMode);
1224 template bool compare_unary_operation_single_output(Operation, float, float16,
1225                                                     double, RoundingMode);
1226 template bool compare_unary_operation_single_output(Operation, double, float16,
1227                                                     double, RoundingMode);
1228 template bool compare_unary_operation_single_output(Operation, long double,
1229                                                     float16, double,
1230                                                     RoundingMode);
1231 #endif
1232 
1233 template <typename T>
compare_unary_operation_two_outputs(Operation op,T input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding)1234 bool compare_unary_operation_two_outputs(Operation op, T input,
1235                                          const BinaryOutput<T> &libc_result,
1236                                          double ulp_tolerance,
1237                                          RoundingMode rounding) {
1238   int mpfrIntResult;
1239   unsigned int precision = get_precision<T>(ulp_tolerance);
1240   MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
1241                                                        precision, rounding);
1242   double ulp = mpfr_result.ulp(libc_result.f);
1243 
1244   if (mpfrIntResult != libc_result.i)
1245     return false;
1246 
1247   return (ulp <= ulp_tolerance);
1248 }
1249 
1250 template bool compare_unary_operation_two_outputs<float>(
1251     Operation, float, const BinaryOutput<float> &, double, RoundingMode);
1252 template bool compare_unary_operation_two_outputs<double>(
1253     Operation, double, const BinaryOutput<double> &, double, RoundingMode);
1254 template bool compare_unary_operation_two_outputs<long double>(
1255     Operation, long double, const BinaryOutput<long double> &, double,
1256     RoundingMode);
1257 
1258 template <typename T>
compare_binary_operation_two_outputs(Operation op,const BinaryInput<T> & input,const BinaryOutput<T> & libc_result,double ulp_tolerance,RoundingMode rounding)1259 bool compare_binary_operation_two_outputs(Operation op,
1260                                           const BinaryInput<T> &input,
1261                                           const BinaryOutput<T> &libc_result,
1262                                           double ulp_tolerance,
1263                                           RoundingMode rounding) {
1264   int mpfrIntResult;
1265   unsigned int precision = get_precision<T>(ulp_tolerance);
1266   MPFRNumber mpfr_result = binary_operation_two_outputs(
1267       op, input.x, input.y, mpfrIntResult, precision, rounding);
1268   double ulp = mpfr_result.ulp(libc_result.f);
1269 
1270   if (mpfrIntResult != libc_result.i) {
1271     if (op == Operation::RemQuo) {
1272       if ((0x7 & mpfrIntResult) != (0x7 & libc_result.i))
1273         return false;
1274     } else {
1275       return false;
1276     }
1277   }
1278 
1279   return (ulp <= ulp_tolerance);
1280 }
1281 
1282 template bool compare_binary_operation_two_outputs<float>(
1283     Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
1284     RoundingMode);
1285 template bool compare_binary_operation_two_outputs<double>(
1286     Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
1287     double, RoundingMode);
1288 template bool compare_binary_operation_two_outputs<long double>(
1289     Operation, const BinaryInput<long double> &,
1290     const BinaryOutput<long double> &, double, RoundingMode);
1291 
1292 template <typename InputType, typename OutputType>
compare_binary_operation_one_output(Operation op,const BinaryInput<InputType> & input,OutputType libc_result,double ulp_tolerance,RoundingMode rounding)1293 bool compare_binary_operation_one_output(Operation op,
1294                                          const BinaryInput<InputType> &input,
1295                                          OutputType libc_result,
1296                                          double ulp_tolerance,
1297                                          RoundingMode rounding) {
1298   unsigned int precision = get_precision<InputType>(ulp_tolerance);
1299   MPFRNumber mpfr_result =
1300       binary_operation_one_output(op, input.x, input.y, precision, rounding);
1301   double ulp = mpfr_result.ulp(libc_result);
1302 
1303   return (ulp <= ulp_tolerance);
1304 }
1305 
1306 template bool compare_binary_operation_one_output(Operation,
1307                                                   const BinaryInput<float> &,
1308                                                   float, double, RoundingMode);
1309 template bool compare_binary_operation_one_output(Operation,
1310                                                   const BinaryInput<double> &,
1311                                                   double, double, RoundingMode);
1312 template bool
1313 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
1314                                     float, double, RoundingMode);
1315 template bool
1316 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
1317                                     double, double, RoundingMode);
1318 template bool
1319 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
1320                                     long double, double, RoundingMode);
1321 
1322 template bool compare_binary_operation_one_output(Operation,
1323                                                   const BinaryInput<double> &,
1324                                                   float, double, RoundingMode);
1325 #ifdef LIBC_TYPES_HAS_FLOAT16
1326 template bool compare_binary_operation_one_output(Operation,
1327                                                   const BinaryInput<float16> &,
1328                                                   float16, double,
1329                                                   RoundingMode);
1330 template bool compare_binary_operation_one_output(Operation,
1331                                                   const BinaryInput<float> &,
1332                                                   float16, double,
1333                                                   RoundingMode);
1334 template bool compare_binary_operation_one_output(Operation,
1335                                                   const BinaryInput<double> &,
1336                                                   float16, double,
1337                                                   RoundingMode);
1338 template bool
1339 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
1340                                     float16, double, RoundingMode);
1341 #endif
1342 
1343 template <typename InputType, typename OutputType>
compare_ternary_operation_one_output(Operation op,const TernaryInput<InputType> & input,OutputType libc_result,double ulp_tolerance,RoundingMode rounding)1344 bool compare_ternary_operation_one_output(Operation op,
1345                                           const TernaryInput<InputType> &input,
1346                                           OutputType libc_result,
1347                                           double ulp_tolerance,
1348                                           RoundingMode rounding) {
1349   unsigned int precision = get_precision<InputType>(ulp_tolerance);
1350   MPFRNumber mpfr_result = ternary_operation_one_output(
1351       op, input.x, input.y, input.z, precision, rounding);
1352   double ulp = mpfr_result.ulp(libc_result);
1353 
1354   return (ulp <= ulp_tolerance);
1355 }
1356 
1357 template bool compare_ternary_operation_one_output(Operation,
1358                                                    const TernaryInput<float> &,
1359                                                    float, double, RoundingMode);
1360 template bool compare_ternary_operation_one_output(Operation,
1361                                                    const TernaryInput<double> &,
1362                                                    float, double, RoundingMode);
1363 template bool compare_ternary_operation_one_output(Operation,
1364                                                    const TernaryInput<double> &,
1365                                                    double, double,
1366                                                    RoundingMode);
1367 template bool compare_ternary_operation_one_output(
1368     Operation, const TernaryInput<long double> &, float, double, RoundingMode);
1369 template bool compare_ternary_operation_one_output(
1370     Operation, const TernaryInput<long double> &, double, double, RoundingMode);
1371 template bool
1372 compare_ternary_operation_one_output(Operation,
1373                                      const TernaryInput<long double> &,
1374                                      long double, double, RoundingMode);
1375 
1376 #ifdef LIBC_TYPES_HAS_FLOAT16
1377 template bool compare_ternary_operation_one_output(Operation,
1378                                                    const TernaryInput<float> &,
1379                                                    float16, double,
1380                                                    RoundingMode);
1381 template bool compare_ternary_operation_one_output(Operation,
1382                                                    const TernaryInput<double> &,
1383                                                    float16, double,
1384                                                    RoundingMode);
1385 template bool
1386 compare_ternary_operation_one_output(Operation,
1387                                      const TernaryInput<long double> &, float16,
1388                                      double, RoundingMode);
1389 #endif
1390 
1391 } // namespace internal
1392 
round_to_long(T x,long & result)1393 template <typename T> bool round_to_long(T x, long &result) {
1394   MPFRNumber mpfr(x);
1395   return mpfr.round_to_long(result);
1396 }
1397 
1398 template bool round_to_long<float>(float, long &);
1399 template bool round_to_long<double>(double, long &);
1400 template bool round_to_long<long double>(long double, long &);
1401 #ifdef LIBC_TYPES_HAS_FLOAT16
1402 template bool round_to_long<float16>(float16, long &);
1403 #endif
1404 
round_to_long(T x,RoundingMode mode,long & result)1405 template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
1406   MPFRNumber mpfr(x);
1407   return mpfr.round_to_long(get_mpfr_rounding_mode(mode), result);
1408 }
1409 
1410 template bool round_to_long<float>(float, RoundingMode, long &);
1411 template bool round_to_long<double>(double, RoundingMode, long &);
1412 template bool round_to_long<long double>(long double, RoundingMode, long &);
1413 #ifdef LIBC_TYPES_HAS_FLOAT16
1414 template bool round_to_long<float16>(float16, RoundingMode, long &);
1415 #endif
1416 
round(T x,RoundingMode mode)1417 template <typename T> T round(T x, RoundingMode mode) {
1418   MPFRNumber mpfr(x);
1419   MPFRNumber result = mpfr.rint(get_mpfr_rounding_mode(mode));
1420   return result.as<T>();
1421 }
1422 
1423 template float round<float>(float, RoundingMode);
1424 template double round<double>(double, RoundingMode);
1425 template long double round<long double>(long double, RoundingMode);
1426 #ifdef LIBC_TYPES_HAS_FLOAT16
1427 template float16 round<float16>(float16, RoundingMode);
1428 #endif
1429 
1430 } // namespace mpfr
1431 } // namespace testing
1432 } // namespace LIBC_NAMESPACE_DECL
1433