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