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/StringView.h"
12 #include "src/__support/FPUtil/FPBits.h"
13 #include "src/__support/architectures.h"
14 #include "utils/UnitTest/FPMatcher.h"
15 
16 #include <cmath>
17 #include <fenv.h>
18 #include <memory>
19 #include <stdint.h>
20 #include <string>
21 
22 #ifdef CUSTOM_MPFR_INCLUDER
23 // Some downstream repos are monoliths carrying MPFR sources in their third
24 // party directory. In such repos, including the MPFR header as
25 // `#include <mpfr.h>` is either disallowed or not possible. If that is the
26 // case, a file named `CustomMPFRIncluder.h` should be added through which the
27 // MPFR header can be included in manner allowed in that repo.
28 #include "CustomMPFRIncluder.h"
29 #else
30 #include <mpfr.h>
31 #endif
32 
33 template <typename T> using FPBits = __llvm_libc::fputil::FPBits<T>;
34 
35 namespace __llvm_libc {
36 namespace testing {
37 namespace mpfr {
38 
39 template <typename T> struct Precision;
40 
41 template <> struct Precision<float> {
42   static constexpr unsigned int VALUE = 24;
43 };
44 
45 template <> struct Precision<double> {
46   static constexpr unsigned int VALUE = 53;
47 };
48 
49 #if !(defined(LLVM_LIBC_ARCH_X86))
50 template <> struct Precision<long double> {
51   static constexpr unsigned int VALUE = 64;
52 };
53 #else
54 template <> struct Precision<long double> {
55   static constexpr unsigned int VALUE = 113;
56 };
57 #endif
58 
59 // A precision value which allows sufficiently large additional
60 // precision compared to the floating point precision.
61 template <typename T> struct ExtraPrecision;
62 
63 template <> struct ExtraPrecision<float> {
64   static constexpr unsigned int VALUE = 128;
65 };
66 
67 template <> struct ExtraPrecision<double> {
68   static constexpr unsigned int VALUE = 256;
69 };
70 
71 template <> struct ExtraPrecision<long double> {
72   static constexpr unsigned int VALUE = 256;
73 };
74 
75 // If the ulp tolerance is less than or equal to 0.5, we would check that the
76 // result is rounded correctly with respect to the rounding mode by using the
77 // same precision as the inputs.
78 template <typename T>
79 static inline unsigned int get_precision(double ulp_tolerance) {
80   if (ulp_tolerance <= 0.5) {
81     return Precision<T>::VALUE;
82   } else {
83     return ExtraPrecision<T>::VALUE;
84   }
85 }
86 
87 static inline mpfr_rnd_t get_mpfr_rounding_mode(RoundingMode mode) {
88   switch (mode) {
89   case RoundingMode::Upward:
90     return MPFR_RNDU;
91     break;
92   case RoundingMode::Downward:
93     return MPFR_RNDD;
94     break;
95   case RoundingMode::TowardZero:
96     return MPFR_RNDZ;
97     break;
98   case RoundingMode::Nearest:
99     return MPFR_RNDN;
100     break;
101   }
102 }
103 
104 int get_fe_rounding(RoundingMode mode) {
105   switch (mode) {
106   case RoundingMode::Upward:
107     return FE_UPWARD;
108     break;
109   case RoundingMode::Downward:
110     return FE_DOWNWARD;
111     break;
112   case RoundingMode::TowardZero:
113     return FE_TOWARDZERO;
114     break;
115   case RoundingMode::Nearest:
116     return FE_TONEAREST;
117     break;
118   }
119 }
120 
121 ForceRoundingMode::ForceRoundingMode(RoundingMode mode) {
122   old_rounding_mode = fegetround();
123   rounding_mode = get_fe_rounding(mode);
124   if (old_rounding_mode != rounding_mode)
125     fesetround(rounding_mode);
126 }
127 
128 ForceRoundingMode::~ForceRoundingMode() {
129   if (old_rounding_mode != rounding_mode)
130     fesetround(old_rounding_mode);
131 }
132 
133 class MPFRNumber {
134   unsigned int mpfr_precision;
135   mpfr_rnd_t mpfr_rounding;
136 
137   mpfr_t value;
138 
139 public:
140   MPFRNumber() : mpfr_precision(256), mpfr_rounding(MPFR_RNDN) {
141     mpfr_init2(value, mpfr_precision);
142   }
143 
144   // We use explicit EnableIf specializations to disallow implicit
145   // conversions. Implicit conversions can potentially lead to loss of
146   // precision.
147   template <typename XType,
148             cpp::EnableIfType<cpp::IsSame<float, XType>::Value, int> = 0>
149   explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
150                       RoundingMode rounding = RoundingMode::Nearest)
151       : mpfr_precision(precision),
152         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
153     mpfr_init2(value, mpfr_precision);
154     mpfr_set_flt(value, x, mpfr_rounding);
155   }
156 
157   template <typename XType,
158             cpp::EnableIfType<cpp::IsSame<double, XType>::Value, int> = 0>
159   explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
160                       RoundingMode rounding = RoundingMode::Nearest)
161       : mpfr_precision(precision),
162         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
163     mpfr_init2(value, mpfr_precision);
164     mpfr_set_d(value, x, mpfr_rounding);
165   }
166 
167   template <typename XType,
168             cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
169   explicit MPFRNumber(XType x, int precision = ExtraPrecision<XType>::VALUE,
170                       RoundingMode rounding = RoundingMode::Nearest)
171       : mpfr_precision(precision),
172         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
173     mpfr_init2(value, mpfr_precision);
174     mpfr_set_ld(value, x, mpfr_rounding);
175   }
176 
177   template <typename XType,
178             cpp::EnableIfType<cpp::IsIntegral<XType>::Value, int> = 0>
179   explicit MPFRNumber(XType x, int precision = ExtraPrecision<float>::VALUE,
180                       RoundingMode rounding = RoundingMode::Nearest)
181       : mpfr_precision(precision),
182         mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
183     mpfr_init2(value, mpfr_precision);
184     mpfr_set_sj(value, x, mpfr_rounding);
185   }
186 
187   MPFRNumber(const MPFRNumber &other)
188       : mpfr_precision(other.mpfr_precision),
189         mpfr_rounding(other.mpfr_rounding) {
190     mpfr_init2(value, mpfr_precision);
191     mpfr_set(value, other.value, mpfr_rounding);
192   }
193 
194   ~MPFRNumber() { mpfr_clear(value); }
195 
196   MPFRNumber &operator=(const MPFRNumber &rhs) {
197     mpfr_precision = rhs.mpfr_precision;
198     mpfr_rounding = rhs.mpfr_rounding;
199     mpfr_set(value, rhs.value, mpfr_rounding);
200     return *this;
201   }
202 
203   MPFRNumber abs() const {
204     MPFRNumber result(*this);
205     mpfr_abs(result.value, value, mpfr_rounding);
206     return result;
207   }
208 
209   MPFRNumber ceil() const {
210     MPFRNumber result(*this);
211     mpfr_ceil(result.value, value);
212     return result;
213   }
214 
215   MPFRNumber cos() const {
216     MPFRNumber result(*this);
217     mpfr_cos(result.value, value, mpfr_rounding);
218     return result;
219   }
220 
221   MPFRNumber exp() const {
222     MPFRNumber result(*this);
223     mpfr_exp(result.value, value, mpfr_rounding);
224     return result;
225   }
226 
227   MPFRNumber exp2() const {
228     MPFRNumber result(*this);
229     mpfr_exp2(result.value, value, mpfr_rounding);
230     return result;
231   }
232 
233   MPFRNumber expm1() const {
234     MPFRNumber result(*this);
235     mpfr_expm1(result.value, value, mpfr_rounding);
236     return result;
237   }
238 
239   MPFRNumber floor() const {
240     MPFRNumber result(*this);
241     mpfr_floor(result.value, value);
242     return result;
243   }
244 
245   MPFRNumber frexp(int &exp) {
246     MPFRNumber result(*this);
247     mpfr_exp_t resultExp;
248     mpfr_frexp(&resultExp, result.value, value, mpfr_rounding);
249     exp = resultExp;
250     return result;
251   }
252 
253   MPFRNumber hypot(const MPFRNumber &b) {
254     MPFRNumber result(*this);
255     mpfr_hypot(result.value, value, b.value, mpfr_rounding);
256     return result;
257   }
258 
259   MPFRNumber log() const {
260     MPFRNumber result(*this);
261     mpfr_log(result.value, value, mpfr_rounding);
262     return result;
263   }
264 
265   MPFRNumber remquo(const MPFRNumber &divisor, int &quotient) {
266     MPFRNumber remainder(*this);
267     long q;
268     mpfr_remquo(remainder.value, &q, value, divisor.value, mpfr_rounding);
269     quotient = q;
270     return remainder;
271   }
272 
273   MPFRNumber round() const {
274     MPFRNumber result(*this);
275     mpfr_round(result.value, value);
276     return result;
277   }
278 
279   bool round_to_long(long &result) const {
280     // We first calculate the rounded value. This way, when converting
281     // to long using mpfr_get_si, the rounding direction of MPFR_RNDN
282     // (or any other rounding mode), does not have an influence.
283     MPFRNumber roundedValue = round();
284     mpfr_clear_erangeflag();
285     result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
286     return mpfr_erangeflag_p();
287   }
288 
289   bool round_to_long(mpfr_rnd_t rnd, long &result) const {
290     MPFRNumber rint_result(*this);
291     mpfr_rint(rint_result.value, value, rnd);
292     return rint_result.round_to_long(result);
293   }
294 
295   MPFRNumber rint(mpfr_rnd_t rnd) const {
296     MPFRNumber result(*this);
297     mpfr_rint(result.value, value, rnd);
298     return result;
299   }
300 
301   MPFRNumber mod_2pi() const {
302     MPFRNumber result(0.0, 1280);
303     MPFRNumber _2pi(0.0, 1280);
304     mpfr_const_pi(_2pi.value, MPFR_RNDN);
305     mpfr_mul_si(_2pi.value, _2pi.value, 2, MPFR_RNDN);
306     mpfr_fmod(result.value, value, _2pi.value, MPFR_RNDN);
307     return result;
308   }
309 
310   MPFRNumber mod_pi_over_2() const {
311     MPFRNumber result(0.0, 1280);
312     MPFRNumber pi_over_2(0.0, 1280);
313     mpfr_const_pi(pi_over_2.value, MPFR_RNDN);
314     mpfr_mul_d(pi_over_2.value, pi_over_2.value, 0.5, MPFR_RNDN);
315     mpfr_fmod(result.value, value, pi_over_2.value, MPFR_RNDN);
316     return result;
317   }
318 
319   MPFRNumber mod_pi_over_4() const {
320     MPFRNumber result(0.0, 1280);
321     MPFRNumber pi_over_4(0.0, 1280);
322     mpfr_const_pi(pi_over_4.value, MPFR_RNDN);
323     mpfr_mul_d(pi_over_4.value, pi_over_4.value, 0.25, MPFR_RNDN);
324     mpfr_fmod(result.value, value, pi_over_4.value, MPFR_RNDN);
325     return result;
326   }
327 
328   MPFRNumber sin() const {
329     MPFRNumber result(*this);
330     mpfr_sin(result.value, value, mpfr_rounding);
331     return result;
332   }
333 
334   MPFRNumber sqrt() const {
335     MPFRNumber result(*this);
336     mpfr_sqrt(result.value, value, mpfr_rounding);
337     return result;
338   }
339 
340   MPFRNumber tan() const {
341     MPFRNumber result(*this);
342     mpfr_tan(result.value, value, mpfr_rounding);
343     return result;
344   }
345 
346   MPFRNumber trunc() const {
347     MPFRNumber result(*this);
348     mpfr_trunc(result.value, value);
349     return result;
350   }
351 
352   MPFRNumber fma(const MPFRNumber &b, const MPFRNumber &c) {
353     MPFRNumber result(*this);
354     mpfr_fma(result.value, value, b.value, c.value, mpfr_rounding);
355     return result;
356   }
357 
358   std::string str() const {
359     // 200 bytes should be more than sufficient to hold a 100-digit number
360     // plus additional bytes for the decimal point, '-' sign etc.
361     constexpr size_t printBufSize = 200;
362     char buffer[printBufSize];
363     mpfr_snprintf(buffer, printBufSize, "%100.50Rf", value);
364     cpp::StringView view(buffer);
365     view = view.trim(' ');
366     return std::string(view.data());
367   }
368 
369   // These functions are useful for debugging.
370   template <typename T> T as() const;
371 
372   template <> float as<float>() const {
373     return mpfr_get_flt(value, mpfr_rounding);
374   }
375   template <> double as<double>() const {
376     return mpfr_get_d(value, mpfr_rounding);
377   }
378   template <> long double as<long double>() const {
379     return mpfr_get_ld(value, mpfr_rounding);
380   }
381 
382   void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
383 
384   // Return the ULP (units-in-the-last-place) difference between the
385   // stored MPFR and a floating point number.
386   //
387   // We define ULP difference as follows:
388   //   If exponents of this value and the |input| are same, then:
389   //     ULP(this_value, input) = abs(this_value - input) / eps(input)
390   //   else:
391   //     max = max(abs(this_value), abs(input))
392   //     min = min(abs(this_value), abs(input))
393   //     maxExponent = exponent(max)
394   //     ULP(this_value, input) = (max - 2^maxExponent) / eps(max) +
395   //                              (2^maxExponent - min) / eps(min)
396   //
397   // Remarks:
398   // 1. A ULP of 0.0 will imply that the value is correctly rounded.
399   // 2. We expect that this value and the value to be compared (the [input]
400   //    argument) are reasonable close, and we will provide an upper bound
401   //    of ULP value for testing.  Morever, most of the fractional parts of
402   //    ULP value do not matter much, so using double as the return type
403   //    should be good enough.
404   // 3. For close enough values (values which don't diff in their exponent by
405   //    not more than 1), a ULP difference of N indicates a bit distance
406   //    of N between this number and [input].
407   // 4. A values of +0.0 and -0.0 are treated as equal.
408   template <typename T>
409   cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, double> ulp(T input) {
410     T thisAsT = as<T>();
411     if (thisAsT == input)
412       return T(0.0);
413 
414     int thisExponent = fputil::FPBits<T>(thisAsT).get_exponent();
415     int inputExponent = fputil::FPBits<T>(input).get_exponent();
416     // Adjust the exponents for denormal numbers.
417     if (fputil::FPBits<T>(thisAsT).get_unbiased_exponent() == 0)
418       ++thisExponent;
419     if (fputil::FPBits<T>(input).get_unbiased_exponent() == 0)
420       ++inputExponent;
421 
422     if (thisAsT * input < 0 || thisExponent == inputExponent) {
423       MPFRNumber inputMPFR(input);
424       mpfr_sub(inputMPFR.value, value, inputMPFR.value, MPFR_RNDN);
425       mpfr_abs(inputMPFR.value, inputMPFR.value, MPFR_RNDN);
426       mpfr_mul_2si(inputMPFR.value, inputMPFR.value,
427                    -thisExponent + int(fputil::MantissaWidth<T>::VALUE),
428                    MPFR_RNDN);
429       return inputMPFR.as<double>();
430     }
431 
432     // If the control reaches here, it means that this number and input are
433     // of the same sign but different exponent. In such a case, ULP error is
434     // calculated as sum of two parts.
435     thisAsT = std::abs(thisAsT);
436     input = std::abs(input);
437     T min = thisAsT > input ? input : thisAsT;
438     T max = thisAsT > input ? thisAsT : input;
439     int minExponent = fputil::FPBits<T>(min).get_exponent();
440     int maxExponent = fputil::FPBits<T>(max).get_exponent();
441     // Adjust the exponents for denormal numbers.
442     if (fputil::FPBits<T>(min).get_unbiased_exponent() == 0)
443       ++minExponent;
444     if (fputil::FPBits<T>(max).get_unbiased_exponent() == 0)
445       ++maxExponent;
446 
447     MPFRNumber minMPFR(min);
448     MPFRNumber maxMPFR(max);
449 
450     MPFRNumber pivot(uint32_t(1));
451     mpfr_mul_2si(pivot.value, pivot.value, maxExponent, MPFR_RNDN);
452 
453     mpfr_sub(minMPFR.value, pivot.value, minMPFR.value, MPFR_RNDN);
454     mpfr_mul_2si(minMPFR.value, minMPFR.value,
455                  -minExponent + int(fputil::MantissaWidth<T>::VALUE),
456                  MPFR_RNDN);
457 
458     mpfr_sub(maxMPFR.value, maxMPFR.value, pivot.value, MPFR_RNDN);
459     mpfr_mul_2si(maxMPFR.value, maxMPFR.value,
460                  -maxExponent + int(fputil::MantissaWidth<T>::VALUE),
461                  MPFR_RNDN);
462 
463     mpfr_add(minMPFR.value, minMPFR.value, maxMPFR.value, MPFR_RNDN);
464     return minMPFR.as<double>();
465   }
466 };
467 
468 namespace internal {
469 
470 template <typename InputType>
471 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
472 unary_operation(Operation op, InputType input, unsigned int precision,
473                 RoundingMode rounding) {
474   MPFRNumber mpfrInput(input, precision, rounding);
475   switch (op) {
476   case Operation::Abs:
477     return mpfrInput.abs();
478   case Operation::Ceil:
479     return mpfrInput.ceil();
480   case Operation::Cos:
481     return mpfrInput.cos();
482   case Operation::Exp:
483     return mpfrInput.exp();
484   case Operation::Exp2:
485     return mpfrInput.exp2();
486   case Operation::Expm1:
487     return mpfrInput.expm1();
488   case Operation::Floor:
489     return mpfrInput.floor();
490   case Operation::Log:
491     return mpfrInput.log();
492   case Operation::Mod2PI:
493     return mpfrInput.mod_2pi();
494   case Operation::ModPIOver2:
495     return mpfrInput.mod_pi_over_2();
496   case Operation::ModPIOver4:
497     return mpfrInput.mod_pi_over_4();
498   case Operation::Round:
499     return mpfrInput.round();
500   case Operation::Sin:
501     return mpfrInput.sin();
502   case Operation::Sqrt:
503     return mpfrInput.sqrt();
504   case Operation::Tan:
505     return mpfrInput.tan();
506   case Operation::Trunc:
507     return mpfrInput.trunc();
508   default:
509     __builtin_unreachable();
510   }
511 }
512 
513 template <typename InputType>
514 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
515 unary_operation_two_outputs(Operation op, InputType input, int &output,
516                             unsigned int precision, RoundingMode rounding) {
517   MPFRNumber mpfrInput(input, precision, rounding);
518   switch (op) {
519   case Operation::Frexp:
520     return mpfrInput.frexp(output);
521   default:
522     __builtin_unreachable();
523   }
524 }
525 
526 template <typename InputType>
527 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
528 binary_operation_one_output(Operation op, InputType x, InputType y,
529                             unsigned int precision, RoundingMode rounding) {
530   MPFRNumber inputX(x, precision, rounding);
531   MPFRNumber inputY(y, precision, rounding);
532   switch (op) {
533   case Operation::Hypot:
534     return inputX.hypot(inputY);
535   default:
536     __builtin_unreachable();
537   }
538 }
539 
540 template <typename InputType>
541 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
542 binary_operation_two_outputs(Operation op, InputType x, InputType y,
543                              int &output, unsigned int precision,
544                              RoundingMode rounding) {
545   MPFRNumber inputX(x, precision, rounding);
546   MPFRNumber inputY(y, precision, rounding);
547   switch (op) {
548   case Operation::RemQuo:
549     return inputX.remquo(inputY, output);
550   default:
551     __builtin_unreachable();
552   }
553 }
554 
555 template <typename InputType>
556 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
557 ternary_operation_one_output(Operation op, InputType x, InputType y,
558                              InputType z, unsigned int precision,
559                              RoundingMode rounding) {
560   // For FMA function, we just need to compare with the mpfr_fma with the same
561   // precision as InputType.  Using higher precision as the intermediate results
562   // to compare might incorrectly fail due to double-rounding errors.
563   MPFRNumber inputX(x, precision, rounding);
564   MPFRNumber inputY(y, precision, rounding);
565   MPFRNumber inputZ(z, precision, rounding);
566   switch (op) {
567   case Operation::Fma:
568     return inputX.fma(inputY, inputZ);
569   default:
570     __builtin_unreachable();
571   }
572 }
573 
574 template <typename T>
575 void explain_unary_operation_single_output_error(Operation op, T input,
576                                                  T matchValue,
577                                                  double ulp_tolerance,
578                                                  RoundingMode rounding,
579                                                  testutils::StreamWrapper &OS) {
580   unsigned int precision = get_precision<T>(ulp_tolerance);
581   MPFRNumber mpfrInput(input, precision);
582   MPFRNumber mpfr_result;
583   mpfr_result = unary_operation(op, input, precision, rounding);
584   MPFRNumber mpfrMatchValue(matchValue);
585   OS << "Match value not within tolerance value of MPFR result:\n"
586      << "  Input decimal: " << mpfrInput.str() << '\n';
587   __llvm_libc::fputil::testing::describeValue("     Input bits: ", input, OS);
588   OS << '\n' << "  Match decimal: " << mpfrMatchValue.str() << '\n';
589   __llvm_libc::fputil::testing::describeValue("     Match bits: ", matchValue,
590                                               OS);
591   OS << '\n' << "    MPFR result: " << mpfr_result.str() << '\n';
592   __llvm_libc::fputil::testing::describeValue(
593       "   MPFR rounded: ", mpfr_result.as<T>(), OS);
594   OS << '\n';
595   OS << "      ULP error: " << std::to_string(mpfr_result.ulp(matchValue))
596      << '\n';
597 }
598 
599 template void
600 explain_unary_operation_single_output_error<float>(Operation op, float, float,
601                                                    double, RoundingMode,
602                                                    testutils::StreamWrapper &);
603 template void explain_unary_operation_single_output_error<double>(
604     Operation op, double, double, double, RoundingMode,
605     testutils::StreamWrapper &);
606 template void explain_unary_operation_single_output_error<long double>(
607     Operation op, long double, long double, double, RoundingMode,
608     testutils::StreamWrapper &);
609 
610 template <typename T>
611 void explain_unary_operation_two_outputs_error(
612     Operation op, T input, const BinaryOutput<T> &libc_result,
613     double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
614   unsigned int precision = get_precision<T>(ulp_tolerance);
615   MPFRNumber mpfrInput(input, precision);
616   int mpfrIntResult;
617   MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
618                                                        precision, rounding);
619 
620   if (mpfrIntResult != libc_result.i) {
621     OS << "MPFR integral result: " << mpfrIntResult << '\n'
622        << "Libc integral result: " << libc_result.i << '\n';
623   } else {
624     OS << "Integral result from libc matches integral result from MPFR.\n";
625   }
626 
627   MPFRNumber mpfrMatchValue(libc_result.f);
628   OS << "Libc floating point result is not within tolerance value of the MPFR "
629      << "result.\n\n";
630 
631   OS << "            Input decimal: " << mpfrInput.str() << "\n\n";
632 
633   OS << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
634   __llvm_libc::fputil::testing::describeValue(
635       " Libc floating point bits: ", libc_result.f, OS);
636   OS << "\n\n";
637 
638   OS << "              MPFR result: " << mpfr_result.str() << '\n';
639   __llvm_libc::fputil::testing::describeValue(
640       "             MPFR rounded: ", mpfr_result.as<T>(), OS);
641   OS << '\n'
642      << "                ULP error: "
643      << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
644 }
645 
646 template void explain_unary_operation_two_outputs_error<float>(
647     Operation, float, const BinaryOutput<float> &, double, RoundingMode,
648     testutils::StreamWrapper &);
649 template void explain_unary_operation_two_outputs_error<double>(
650     Operation, double, const BinaryOutput<double> &, double, RoundingMode,
651     testutils::StreamWrapper &);
652 template void explain_unary_operation_two_outputs_error<long double>(
653     Operation, long double, const BinaryOutput<long double> &, double,
654     RoundingMode, testutils::StreamWrapper &);
655 
656 template <typename T>
657 void explain_binary_operation_two_outputs_error(
658     Operation op, const BinaryInput<T> &input,
659     const BinaryOutput<T> &libc_result, double ulp_tolerance,
660     RoundingMode rounding, testutils::StreamWrapper &OS) {
661   unsigned int precision = get_precision<T>(ulp_tolerance);
662   MPFRNumber mpfrX(input.x, precision);
663   MPFRNumber mpfrY(input.y, precision);
664   int mpfrIntResult;
665   MPFRNumber mpfr_result = binary_operation_two_outputs(
666       op, input.x, input.y, mpfrIntResult, precision, rounding);
667   MPFRNumber mpfrMatchValue(libc_result.f);
668 
669   OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
670      << "MPFR integral result: " << mpfrIntResult << '\n'
671      << "Libc integral result: " << libc_result.i << '\n'
672      << "Libc floating point result: " << mpfrMatchValue.str() << '\n'
673      << "               MPFR result: " << mpfr_result.str() << '\n';
674   __llvm_libc::fputil::testing::describeValue(
675       "Libc floating point result bits: ", libc_result.f, OS);
676   __llvm_libc::fputil::testing::describeValue(
677       "              MPFR rounded bits: ", mpfr_result.as<T>(), OS);
678   OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
679 }
680 
681 template void explain_binary_operation_two_outputs_error<float>(
682     Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
683     RoundingMode, testutils::StreamWrapper &);
684 template void explain_binary_operation_two_outputs_error<double>(
685     Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
686     double, RoundingMode, testutils::StreamWrapper &);
687 template void explain_binary_operation_two_outputs_error<long double>(
688     Operation, const BinaryInput<long double> &,
689     const BinaryOutput<long double> &, double, RoundingMode,
690     testutils::StreamWrapper &);
691 
692 template <typename T>
693 void explain_binary_operation_one_output_error(
694     Operation op, const BinaryInput<T> &input, T libc_result,
695     double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
696   unsigned int precision = get_precision<T>(ulp_tolerance);
697   MPFRNumber mpfrX(input.x, precision);
698   MPFRNumber mpfrY(input.y, precision);
699   FPBits<T> xbits(input.x);
700   FPBits<T> ybits(input.y);
701   MPFRNumber mpfr_result =
702       binary_operation_one_output(op, input.x, input.y, precision, rounding);
703   MPFRNumber mpfrMatchValue(libc_result);
704 
705   OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
706   __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
707                                               OS);
708   __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
709                                               OS);
710 
711   OS << "Libc result: " << mpfrMatchValue.str() << '\n'
712      << "MPFR result: " << mpfr_result.str() << '\n';
713   __llvm_libc::fputil::testing::describeValue(
714       "Libc floating point result bits: ", libc_result, OS);
715   __llvm_libc::fputil::testing::describeValue(
716       "              MPFR rounded bits: ", mpfr_result.as<T>(), OS);
717   OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
718 }
719 
720 template void explain_binary_operation_one_output_error<float>(
721     Operation, const BinaryInput<float> &, float, double, RoundingMode,
722     testutils::StreamWrapper &);
723 template void explain_binary_operation_one_output_error<double>(
724     Operation, const BinaryInput<double> &, double, double, RoundingMode,
725     testutils::StreamWrapper &);
726 template void explain_binary_operation_one_output_error<long double>(
727     Operation, const BinaryInput<long double> &, long double, double,
728     RoundingMode, testutils::StreamWrapper &);
729 
730 template <typename T>
731 void explain_ternary_operation_one_output_error(
732     Operation op, const TernaryInput<T> &input, T libc_result,
733     double ulp_tolerance, RoundingMode rounding, testutils::StreamWrapper &OS) {
734   unsigned int precision = get_precision<T>(ulp_tolerance);
735   MPFRNumber mpfrX(input.x, precision);
736   MPFRNumber mpfrY(input.y, precision);
737   MPFRNumber mpfrZ(input.z, precision);
738   FPBits<T> xbits(input.x);
739   FPBits<T> ybits(input.y);
740   FPBits<T> zbits(input.z);
741   MPFRNumber mpfr_result = ternary_operation_one_output(
742       op, input.x, input.y, input.z, precision, rounding);
743   MPFRNumber mpfrMatchValue(libc_result);
744 
745   OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
746      << " z: " << mpfrZ.str() << '\n';
747   __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
748                                               OS);
749   __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
750                                               OS);
751   __llvm_libc::fputil::testing::describeValue("Third input bits: ", input.z,
752                                               OS);
753 
754   OS << "Libc result: " << mpfrMatchValue.str() << '\n'
755      << "MPFR result: " << mpfr_result.str() << '\n';
756   __llvm_libc::fputil::testing::describeValue(
757       "Libc floating point result bits: ", libc_result, OS);
758   __llvm_libc::fputil::testing::describeValue(
759       "              MPFR rounded bits: ", mpfr_result.as<T>(), OS);
760   OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
761 }
762 
763 template void explain_ternary_operation_one_output_error<float>(
764     Operation, const TernaryInput<float> &, float, double, RoundingMode,
765     testutils::StreamWrapper &);
766 template void explain_ternary_operation_one_output_error<double>(
767     Operation, const TernaryInput<double> &, double, double, RoundingMode,
768     testutils::StreamWrapper &);
769 template void explain_ternary_operation_one_output_error<long double>(
770     Operation, const TernaryInput<long double> &, long double, double,
771     RoundingMode, testutils::StreamWrapper &);
772 
773 template <typename T>
774 bool compare_unary_operation_single_output(Operation op, T input, T libc_result,
775                                            double ulp_tolerance,
776                                            RoundingMode rounding) {
777   unsigned int precision = get_precision<T>(ulp_tolerance);
778   MPFRNumber mpfr_result;
779   mpfr_result = unary_operation(op, input, precision, rounding);
780   double ulp = mpfr_result.ulp(libc_result);
781   return (ulp <= ulp_tolerance);
782 }
783 
784 template bool compare_unary_operation_single_output<float>(Operation, float,
785                                                            float, double,
786                                                            RoundingMode);
787 template bool compare_unary_operation_single_output<double>(Operation, double,
788                                                             double, double,
789                                                             RoundingMode);
790 template bool compare_unary_operation_single_output<long double>(
791     Operation, long double, long double, double, RoundingMode);
792 
793 template <typename T>
794 bool compare_unary_operation_two_outputs(Operation op, T input,
795                                          const BinaryOutput<T> &libc_result,
796                                          double ulp_tolerance,
797                                          RoundingMode rounding) {
798   int mpfrIntResult;
799   unsigned int precision = get_precision<T>(ulp_tolerance);
800   MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
801                                                        precision, rounding);
802   double ulp = mpfr_result.ulp(libc_result.f);
803 
804   if (mpfrIntResult != libc_result.i)
805     return false;
806 
807   return (ulp <= ulp_tolerance);
808 }
809 
810 template bool compare_unary_operation_two_outputs<float>(
811     Operation, float, const BinaryOutput<float> &, double, RoundingMode);
812 template bool compare_unary_operation_two_outputs<double>(
813     Operation, double, const BinaryOutput<double> &, double, RoundingMode);
814 template bool compare_unary_operation_two_outputs<long double>(
815     Operation, long double, const BinaryOutput<long double> &, double,
816     RoundingMode);
817 
818 template <typename T>
819 bool compare_binary_operation_two_outputs(Operation op,
820                                           const BinaryInput<T> &input,
821                                           const BinaryOutput<T> &libc_result,
822                                           double ulp_tolerance,
823                                           RoundingMode rounding) {
824   int mpfrIntResult;
825   unsigned int precision = get_precision<T>(ulp_tolerance);
826   MPFRNumber mpfr_result = binary_operation_two_outputs(
827       op, input.x, input.y, mpfrIntResult, precision, rounding);
828   double ulp = mpfr_result.ulp(libc_result.f);
829 
830   if (mpfrIntResult != libc_result.i) {
831     if (op == Operation::RemQuo) {
832       if ((0x7 & mpfrIntResult) != (0x7 & libc_result.i))
833         return false;
834     } else {
835       return false;
836     }
837   }
838 
839   return (ulp <= ulp_tolerance);
840 }
841 
842 template bool compare_binary_operation_two_outputs<float>(
843     Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
844     RoundingMode);
845 template bool compare_binary_operation_two_outputs<double>(
846     Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
847     double, RoundingMode);
848 template bool compare_binary_operation_two_outputs<long double>(
849     Operation, const BinaryInput<long double> &,
850     const BinaryOutput<long double> &, double, RoundingMode);
851 
852 template <typename T>
853 bool compare_binary_operation_one_output(Operation op,
854                                          const BinaryInput<T> &input,
855                                          T libc_result, double ulp_tolerance,
856                                          RoundingMode rounding) {
857   unsigned int precision = get_precision<T>(ulp_tolerance);
858   MPFRNumber mpfr_result =
859       binary_operation_one_output(op, input.x, input.y, precision, rounding);
860   double ulp = mpfr_result.ulp(libc_result);
861 
862   return (ulp <= ulp_tolerance);
863 }
864 
865 template bool compare_binary_operation_one_output<float>(
866     Operation, const BinaryInput<float> &, float, double, RoundingMode);
867 template bool compare_binary_operation_one_output<double>(
868     Operation, const BinaryInput<double> &, double, double, RoundingMode);
869 template bool compare_binary_operation_one_output<long double>(
870     Operation, const BinaryInput<long double> &, long double, double,
871     RoundingMode);
872 
873 template <typename T>
874 bool compare_ternary_operation_one_output(Operation op,
875                                           const TernaryInput<T> &input,
876                                           T libc_result, double ulp_tolerance,
877                                           RoundingMode rounding) {
878   unsigned int precision = get_precision<T>(ulp_tolerance);
879   MPFRNumber mpfr_result = ternary_operation_one_output(
880       op, input.x, input.y, input.z, precision, rounding);
881   double ulp = mpfr_result.ulp(libc_result);
882 
883   return (ulp <= ulp_tolerance);
884 }
885 
886 template bool compare_ternary_operation_one_output<float>(
887     Operation, const TernaryInput<float> &, float, double, RoundingMode);
888 template bool compare_ternary_operation_one_output<double>(
889     Operation, const TernaryInput<double> &, double, double, RoundingMode);
890 template bool compare_ternary_operation_one_output<long double>(
891     Operation, const TernaryInput<long double> &, long double, double,
892     RoundingMode);
893 
894 } // namespace internal
895 
896 template <typename T> bool round_to_long(T x, long &result) {
897   MPFRNumber mpfr(x);
898   return mpfr.round_to_long(result);
899 }
900 
901 template bool round_to_long<float>(float, long &);
902 template bool round_to_long<double>(double, long &);
903 template bool round_to_long<long double>(long double, long &);
904 
905 template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
906   MPFRNumber mpfr(x);
907   return mpfr.round_to_long(get_mpfr_rounding_mode(mode), result);
908 }
909 
910 template bool round_to_long<float>(float, RoundingMode, long &);
911 template bool round_to_long<double>(double, RoundingMode, long &);
912 template bool round_to_long<long double>(long double, RoundingMode, long &);
913 
914 template <typename T> T round(T x, RoundingMode mode) {
915   MPFRNumber mpfr(x);
916   MPFRNumber result = mpfr.rint(get_mpfr_rounding_mode(mode));
917   return result.as<T>();
918 }
919 
920 template float round<float>(float, RoundingMode);
921 template double round<double>(double, RoundingMode);
922 template long double round<long double>(long double, RoundingMode);
923 
924 } // namespace mpfr
925 } // namespace testing
926 } // namespace __llvm_libc
927