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 "utils/FPUtil/FPBits.h"
12 #include "utils/FPUtil/TestHelpers.h"
13 
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/ADT/StringRef.h"
16 
17 #include <memory>
18 #include <stdint.h>
19 #include <string>
20 
21 #ifdef CUSTOM_MPFR_INCLUDER
22 // Some downstream repos are monoliths carrying MPFR sources in their third
23 // party directory. In such repos, including the MPFR header as
24 // `#include <mpfr.h>` is either disallowed or not possible. If that is the
25 // case, a file named `CustomMPFRIncluder.h` should be added through which the
26 // MPFR header can be included in manner allowed in that repo.
27 #include "CustomMPFRIncluder.h"
28 #else
29 #include <mpfr.h>
30 #endif
31 
32 template <typename T> using FPBits = __llvm_libc::fputil::FPBits<T>;
33 
34 namespace __llvm_libc {
35 namespace testing {
36 namespace mpfr {
37 
38 class MPFRNumber {
39   // A precision value which allows sufficiently large additional
40   // precision even compared to quad-precision floating point values.
41   static constexpr unsigned int mpfrPrecision = 128;
42 
43   mpfr_t value;
44 
45 public:
46   MPFRNumber() { mpfr_init2(value, mpfrPrecision); }
47 
48   // We use explicit EnableIf specializations to disallow implicit
49   // conversions. Implicit conversions can potentially lead to loss of
50   // precision.
51   template <typename XType,
52             cpp::EnableIfType<cpp::IsSame<float, XType>::Value, int> = 0>
53   explicit MPFRNumber(XType x) {
54     mpfr_init2(value, mpfrPrecision);
55     mpfr_set_flt(value, x, MPFR_RNDN);
56   }
57 
58   template <typename XType,
59             cpp::EnableIfType<cpp::IsSame<double, XType>::Value, int> = 0>
60   explicit MPFRNumber(XType x) {
61     mpfr_init2(value, mpfrPrecision);
62     mpfr_set_d(value, x, MPFR_RNDN);
63   }
64 
65   template <typename XType,
66             cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
67   explicit MPFRNumber(XType x) {
68     mpfr_init2(value, mpfrPrecision);
69     mpfr_set_ld(value, x, MPFR_RNDN);
70   }
71 
72   template <typename XType,
73             cpp::EnableIfType<cpp::IsIntegral<XType>::Value, int> = 0>
74   explicit MPFRNumber(XType x) {
75     mpfr_init2(value, mpfrPrecision);
76     mpfr_set_sj(value, x, MPFR_RNDN);
77   }
78 
79   MPFRNumber(const MPFRNumber &other) {
80     mpfr_set(value, other.value, MPFR_RNDN);
81   }
82 
83   ~MPFRNumber() {
84     mpfr_clear(value);
85   }
86 
87   MPFRNumber &operator=(const MPFRNumber &rhs) {
88     mpfr_set(value, rhs.value, MPFR_RNDN);
89     return *this;
90   }
91 
92   MPFRNumber abs() const {
93     MPFRNumber result;
94     mpfr_abs(result.value, value, MPFR_RNDN);
95     return result;
96   }
97 
98   MPFRNumber ceil() const {
99     MPFRNumber result;
100     mpfr_ceil(result.value, value);
101     return result;
102   }
103 
104   MPFRNumber cos() const {
105     MPFRNumber result;
106     mpfr_cos(result.value, value, MPFR_RNDN);
107     return result;
108   }
109 
110   MPFRNumber exp() const {
111     MPFRNumber result;
112     mpfr_exp(result.value, value, MPFR_RNDN);
113     return result;
114   }
115 
116   MPFRNumber exp2() const {
117     MPFRNumber result;
118     mpfr_exp2(result.value, value, MPFR_RNDN);
119     return result;
120   }
121 
122   MPFRNumber floor() const {
123     MPFRNumber result;
124     mpfr_floor(result.value, value);
125     return result;
126   }
127 
128   MPFRNumber frexp(int &exp) {
129     MPFRNumber result;
130     mpfr_exp_t resultExp;
131     mpfr_frexp(&resultExp, result.value, value, MPFR_RNDN);
132     exp = resultExp;
133     return result;
134   }
135 
136   MPFRNumber hypot(const MPFRNumber &b) {
137     MPFRNumber result;
138     mpfr_hypot(result.value, value, b.value, MPFR_RNDN);
139     return result;
140   }
141 
142   MPFRNumber remquo(const MPFRNumber &divisor, int &quotient) {
143     MPFRNumber remainder;
144     long q;
145     mpfr_remquo(remainder.value, &q, value, divisor.value, MPFR_RNDN);
146     quotient = q;
147     return remainder;
148   }
149 
150   MPFRNumber round() const {
151     MPFRNumber result;
152     mpfr_round(result.value, value);
153     return result;
154   }
155 
156   bool roundToLong(long &result) const {
157     // We first calculate the rounded value. This way, when converting
158     // to long using mpfr_get_si, the rounding direction of MPFR_RNDN
159     // (or any other rounding mode), does not have an influence.
160     MPFRNumber roundedValue = round();
161     mpfr_clear_erangeflag();
162     result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
163     return mpfr_erangeflag_p();
164   }
165 
166   bool roundToLong(mpfr_rnd_t rnd, long &result) const {
167     MPFRNumber rint_result;
168     mpfr_rint(rint_result.value, value, rnd);
169     return rint_result.roundToLong(result);
170   }
171 
172   MPFRNumber rint(mpfr_rnd_t rnd) const {
173     MPFRNumber result;
174     mpfr_rint(result.value, value, rnd);
175     return result;
176   }
177 
178   MPFRNumber sin() const {
179     MPFRNumber result;
180     mpfr_sin(result.value, value, MPFR_RNDN);
181     return result;
182   }
183 
184   MPFRNumber sqrt() const {
185     MPFRNumber result;
186     mpfr_sqrt(result.value, value, MPFR_RNDN);
187     return result;
188   }
189 
190   MPFRNumber trunc() const {
191     MPFRNumber result;
192     mpfr_trunc(result.value, value);
193     return result;
194   }
195 
196   std::string str() const {
197     // 200 bytes should be more than sufficient to hold a 100-digit number
198     // plus additional bytes for the decimal point, '-' sign etc.
199     constexpr size_t printBufSize = 200;
200     char buffer[printBufSize];
201     mpfr_snprintf(buffer, printBufSize, "%100.50Rf", value);
202     llvm::StringRef ref(buffer);
203     ref = ref.trim();
204     return ref.str();
205   }
206 
207   // These functions are useful for debugging.
208   template <typename T> T as() const;
209 
210   template <> float as<float>() const { return mpfr_get_flt(value, MPFR_RNDN); }
211   template <> double as<double>() const { return mpfr_get_d(value, MPFR_RNDN); }
212   template <> long double as<long double>() const {
213     return mpfr_get_ld(value, MPFR_RNDN);
214   }
215 
216   void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
217 
218   // Return the ULP (units-in-the-last-place) difference between the
219   // stored MPFR and a floating point number.
220   //
221   // We define:
222   //   ULP(mpfr_value, value) = abs(mpfr_value - value) / eps(value)
223   //
224   // Remarks:
225   // 1. ULP < 0.5 will imply that the value is correctly rounded.
226   // 2. We expect that this value and the value to be compared (the [input]
227   //    argument) are reasonable close, and we will provide an upper bound
228   //    of ULP value for testing.  Morever, most of the fractional parts of
229   //    ULP value do not matter much, so using double as the return type
230   //    should be good enough.
231   template <typename T>
232   cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, double> ulp(T input) {
233     fputil::FPBits<T> bits(input);
234     MPFRNumber mpfrInput(input);
235 
236     // abs(value - input)
237     mpfr_sub(mpfrInput.value, value, mpfrInput.value, MPFR_RNDN);
238     mpfr_abs(mpfrInput.value, mpfrInput.value, MPFR_RNDN);
239 
240     // get eps(input)
241     int epsExponent = bits.exponent - fputil::FPBits<T>::exponentBias -
242                       fputil::MantissaWidth<T>::value;
243     if (bits.exponent == 0) {
244       // correcting denormal exponent
245       ++epsExponent;
246     } else if ((bits.mantissa == 0) && (bits.exponent > 1) &&
247                mpfr_less_p(value, mpfrInput.value)) {
248       // when the input is exactly 2^n, distance (epsilon) between the input
249       // and the next floating point number is different from the distance to
250       // the previous floating point number.  So in that case, if the correct
251       // value from MPFR is smaller than the input, we use the smaller epsilon
252       --epsExponent;
253     }
254 
255     // Since eps(value) is of the form 2^e, instead of dividing such number,
256     // we multiply by its inverse 2^{-e}.
257     mpfr_mul_2si(mpfrInput.value, mpfrInput.value, -epsExponent, MPFR_RNDN);
258 
259     return mpfrInput.as<double>();
260   }
261 };
262 
263 namespace internal {
264 
265 template <typename InputType>
266 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
267 unaryOperation(Operation op, InputType input) {
268   MPFRNumber mpfrInput(input);
269   switch (op) {
270   case Operation::Abs:
271     return mpfrInput.abs();
272   case Operation::Ceil:
273     return mpfrInput.ceil();
274   case Operation::Cos:
275     return mpfrInput.cos();
276   case Operation::Exp:
277     return mpfrInput.exp();
278   case Operation::Exp2:
279     return mpfrInput.exp2();
280   case Operation::Floor:
281     return mpfrInput.floor();
282   case Operation::Round:
283     return mpfrInput.round();
284   case Operation::Sin:
285     return mpfrInput.sin();
286   case Operation::Sqrt:
287     return mpfrInput.sqrt();
288   case Operation::Trunc:
289     return mpfrInput.trunc();
290   default:
291     __builtin_unreachable();
292   }
293 }
294 
295 template <typename InputType>
296 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
297 unaryOperationTwoOutputs(Operation op, InputType input, int &output) {
298   MPFRNumber mpfrInput(input);
299   switch (op) {
300   case Operation::Frexp:
301     return mpfrInput.frexp(output);
302   default:
303     __builtin_unreachable();
304   }
305 }
306 
307 template <typename InputType>
308 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
309 binaryOperationOneOutput(Operation op, InputType x, InputType y) {
310   MPFRNumber inputX(x), inputY(y);
311   switch (op) {
312   case Operation::Hypot:
313     return inputX.hypot(inputY);
314   default:
315     __builtin_unreachable();
316   }
317 }
318 
319 template <typename InputType>
320 cpp::EnableIfType<cpp::IsFloatingPointType<InputType>::Value, MPFRNumber>
321 binaryOperationTwoOutputs(Operation op, InputType x, InputType y, int &output) {
322   MPFRNumber inputX(x), inputY(y);
323   switch (op) {
324   case Operation::RemQuo:
325     return inputX.remquo(inputY, output);
326   default:
327     __builtin_unreachable();
328   }
329 }
330 
331 template <typename T>
332 void explainUnaryOperationSingleOutputError(Operation op, T input, T matchValue,
333                                             testutils::StreamWrapper &OS) {
334   MPFRNumber mpfrInput(input);
335   MPFRNumber mpfrResult = unaryOperation(op, input);
336   MPFRNumber mpfrMatchValue(matchValue);
337   FPBits<T> inputBits(input);
338   FPBits<T> matchBits(matchValue);
339   FPBits<T> mpfrResultBits(mpfrResult.as<T>());
340   OS << "Match value not within tolerance value of MPFR result:\n"
341      << "  Input decimal: " << mpfrInput.str() << '\n';
342   __llvm_libc::fputil::testing::describeValue("     Input bits: ", input, OS);
343   OS << '\n' << "  Match decimal: " << mpfrMatchValue.str() << '\n';
344   __llvm_libc::fputil::testing::describeValue("     Match bits: ", matchValue,
345                                               OS);
346   OS << '\n' << "    MPFR result: " << mpfrResult.str() << '\n';
347   __llvm_libc::fputil::testing::describeValue(
348       "   MPFR rounded: ", mpfrResult.as<T>(), OS);
349   OS << '\n';
350   OS << "      ULP error: " << std::to_string(mpfrResult.ulp(matchValue))
351      << '\n';
352 }
353 
354 template void
355 explainUnaryOperationSingleOutputError<float>(Operation op, float, float,
356                                               testutils::StreamWrapper &);
357 template void
358 explainUnaryOperationSingleOutputError<double>(Operation op, double, double,
359                                                testutils::StreamWrapper &);
360 template void explainUnaryOperationSingleOutputError<long double>(
361     Operation op, long double, long double, testutils::StreamWrapper &);
362 
363 template <typename T>
364 void explainUnaryOperationTwoOutputsError(Operation op, T input,
365                                           const BinaryOutput<T> &libcResult,
366                                           testutils::StreamWrapper &OS) {
367   MPFRNumber mpfrInput(input);
368   FPBits<T> inputBits(input);
369   int mpfrIntResult;
370   MPFRNumber mpfrResult = unaryOperationTwoOutputs(op, input, mpfrIntResult);
371 
372   if (mpfrIntResult != libcResult.i) {
373     OS << "MPFR integral result: " << mpfrIntResult << '\n'
374        << "Libc integral result: " << libcResult.i << '\n';
375   } else {
376     OS << "Integral result from libc matches integral result from MPFR.\n";
377   }
378 
379   MPFRNumber mpfrMatchValue(libcResult.f);
380   OS << "Libc floating point result is not within tolerance value of the MPFR "
381      << "result.\n\n";
382 
383   OS << "            Input decimal: " << mpfrInput.str() << "\n\n";
384 
385   OS << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
386   __llvm_libc::fputil::testing::describeValue(
387       " Libc floating point bits: ", libcResult.f, OS);
388   OS << "\n\n";
389 
390   OS << "              MPFR result: " << mpfrResult.str() << '\n';
391   __llvm_libc::fputil::testing::describeValue(
392       "             MPFR rounded: ", mpfrResult.as<T>(), OS);
393   OS << '\n'
394      << "                ULP error: "
395      << std::to_string(mpfrResult.ulp(libcResult.f)) << '\n';
396 }
397 
398 template void explainUnaryOperationTwoOutputsError<float>(
399     Operation, float, const BinaryOutput<float> &, testutils::StreamWrapper &);
400 template void
401 explainUnaryOperationTwoOutputsError<double>(Operation, double,
402                                              const BinaryOutput<double> &,
403                                              testutils::StreamWrapper &);
404 template void explainUnaryOperationTwoOutputsError<long double>(
405     Operation, long double, const BinaryOutput<long double> &,
406     testutils::StreamWrapper &);
407 
408 template <typename T>
409 void explainBinaryOperationTwoOutputsError(Operation op,
410                                            const BinaryInput<T> &input,
411                                            const BinaryOutput<T> &libcResult,
412                                            testutils::StreamWrapper &OS) {
413   MPFRNumber mpfrX(input.x);
414   MPFRNumber mpfrY(input.y);
415   FPBits<T> xbits(input.x);
416   FPBits<T> ybits(input.y);
417   int mpfrIntResult;
418   MPFRNumber mpfrResult =
419       binaryOperationTwoOutputs(op, input.x, input.y, mpfrIntResult);
420   MPFRNumber mpfrMatchValue(libcResult.f);
421 
422   OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
423      << "MPFR integral result: " << mpfrIntResult << '\n'
424      << "Libc integral result: " << libcResult.i << '\n'
425      << "Libc floating point result: " << mpfrMatchValue.str() << '\n'
426      << "               MPFR result: " << mpfrResult.str() << '\n';
427   __llvm_libc::fputil::testing::describeValue(
428       "Libc floating point result bits: ", libcResult.f, OS);
429   __llvm_libc::fputil::testing::describeValue(
430       "              MPFR rounded bits: ", mpfrResult.as<T>(), OS);
431   OS << "ULP error: " << std::to_string(mpfrResult.ulp(libcResult.f)) << '\n';
432 }
433 
434 template void explainBinaryOperationTwoOutputsError<float>(
435     Operation, const BinaryInput<float> &, const BinaryOutput<float> &,
436     testutils::StreamWrapper &);
437 template void explainBinaryOperationTwoOutputsError<double>(
438     Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
439     testutils::StreamWrapper &);
440 template void explainBinaryOperationTwoOutputsError<long double>(
441     Operation, const BinaryInput<long double> &,
442     const BinaryOutput<long double> &, testutils::StreamWrapper &);
443 
444 template <typename T>
445 void explainBinaryOperationOneOutputError(Operation op,
446                                           const BinaryInput<T> &input,
447                                           T libcResult,
448                                           testutils::StreamWrapper &OS) {
449   MPFRNumber mpfrX(input.x);
450   MPFRNumber mpfrY(input.y);
451   FPBits<T> xbits(input.x);
452   FPBits<T> ybits(input.y);
453   MPFRNumber mpfrResult = binaryOperationOneOutput(op, input.x, input.y);
454   MPFRNumber mpfrMatchValue(libcResult);
455 
456   OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
457   __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
458                                               OS);
459   __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
460                                               OS);
461 
462   OS << "Libc result: " << mpfrMatchValue.str() << '\n'
463      << "MPFR result: " << mpfrResult.str() << '\n';
464   __llvm_libc::fputil::testing::describeValue(
465       "Libc floating point result bits: ", libcResult, OS);
466   __llvm_libc::fputil::testing::describeValue(
467       "              MPFR rounded bits: ", mpfrResult.as<T>(), OS);
468   OS << "ULP error: " << std::to_string(mpfrResult.ulp(libcResult)) << '\n';
469 }
470 
471 template void explainBinaryOperationOneOutputError<float>(
472     Operation, const BinaryInput<float> &, float, testutils::StreamWrapper &);
473 template void explainBinaryOperationOneOutputError<double>(
474     Operation, const BinaryInput<double> &, double, testutils::StreamWrapper &);
475 template void explainBinaryOperationOneOutputError<long double>(
476     Operation, const BinaryInput<long double> &, long double,
477     testutils::StreamWrapper &);
478 
479 template <typename T>
480 bool compareUnaryOperationSingleOutput(Operation op, T input, T libcResult,
481                                        double ulpError) {
482   // If the ulp error is exactly 0.5 (i.e a tie), we would check that the result
483   // is rounded to the nearest even.
484   MPFRNumber mpfrResult = unaryOperation(op, input);
485   double ulp = mpfrResult.ulp(libcResult);
486   bool bitsAreEven = ((FPBits<T>(libcResult).bitsAsUInt() & 1) == 0);
487   return (ulp < ulpError) ||
488          ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven));
489 }
490 
491 template bool compareUnaryOperationSingleOutput<float>(Operation, float, float,
492                                                        double);
493 template bool compareUnaryOperationSingleOutput<double>(Operation, double,
494                                                         double, double);
495 template bool compareUnaryOperationSingleOutput<long double>(Operation,
496                                                              long double,
497                                                              long double,
498                                                              double);
499 
500 template <typename T>
501 bool compareUnaryOperationTwoOutputs(Operation op, T input,
502                                      const BinaryOutput<T> &libcResult,
503                                      double ulpError) {
504   int mpfrIntResult;
505   MPFRNumber mpfrResult = unaryOperationTwoOutputs(op, input, mpfrIntResult);
506   double ulp = mpfrResult.ulp(libcResult.f);
507 
508   if (mpfrIntResult != libcResult.i)
509     return false;
510 
511   bool bitsAreEven = ((FPBits<T>(libcResult.f).bitsAsUInt() & 1) == 0);
512   return (ulp < ulpError) ||
513          ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven));
514 }
515 
516 template bool
517 compareUnaryOperationTwoOutputs<float>(Operation, float,
518                                        const BinaryOutput<float> &, double);
519 template bool
520 compareUnaryOperationTwoOutputs<double>(Operation, double,
521                                         const BinaryOutput<double> &, double);
522 template bool compareUnaryOperationTwoOutputs<long double>(
523     Operation, long double, const BinaryOutput<long double> &, double);
524 
525 template <typename T>
526 bool compareBinaryOperationTwoOutputs(Operation op, const BinaryInput<T> &input,
527                                       const BinaryOutput<T> &libcResult,
528                                       double ulpError) {
529   int mpfrIntResult;
530   MPFRNumber mpfrResult =
531       binaryOperationTwoOutputs(op, input.x, input.y, mpfrIntResult);
532   double ulp = mpfrResult.ulp(libcResult.f);
533 
534   if (mpfrIntResult != libcResult.i) {
535     if (op == Operation::RemQuo) {
536       if ((0x7 & mpfrIntResult) != (0x7 & libcResult.i))
537         return false;
538     } else {
539       return false;
540     }
541   }
542 
543   bool bitsAreEven = ((FPBits<T>(libcResult.f).bitsAsUInt() & 1) == 0);
544   return (ulp < ulpError) ||
545          ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven));
546 }
547 
548 template bool
549 compareBinaryOperationTwoOutputs<float>(Operation, const BinaryInput<float> &,
550                                         const BinaryOutput<float> &, double);
551 template bool
552 compareBinaryOperationTwoOutputs<double>(Operation, const BinaryInput<double> &,
553                                          const BinaryOutput<double> &, double);
554 template bool compareBinaryOperationTwoOutputs<long double>(
555     Operation, const BinaryInput<long double> &,
556     const BinaryOutput<long double> &, double);
557 
558 template <typename T>
559 bool compareBinaryOperationOneOutput(Operation op, const BinaryInput<T> &input,
560                                      T libcResult, double ulpError) {
561   MPFRNumber mpfrResult = binaryOperationOneOutput(op, input.x, input.y);
562   double ulp = mpfrResult.ulp(libcResult);
563 
564   bool bitsAreEven = ((FPBits<T>(libcResult).bitsAsUInt() & 1) == 0);
565   return (ulp < ulpError) ||
566          ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven));
567 }
568 
569 template bool compareBinaryOperationOneOutput<float>(Operation,
570                                                      const BinaryInput<float> &,
571                                                      float, double);
572 template bool
573 compareBinaryOperationOneOutput<double>(Operation, const BinaryInput<double> &,
574                                         double, double);
575 template bool compareBinaryOperationOneOutput<long double>(
576     Operation, const BinaryInput<long double> &, long double, double);
577 
578 static mpfr_rnd_t getMPFRRoundingMode(RoundingMode mode) {
579   switch (mode) {
580   case RoundingMode::Upward:
581     return MPFR_RNDU;
582     break;
583   case RoundingMode::Downward:
584     return MPFR_RNDD;
585     break;
586   case RoundingMode::TowardZero:
587     return MPFR_RNDZ;
588     break;
589   case RoundingMode::Nearest:
590     return MPFR_RNDN;
591     break;
592   }
593 }
594 
595 } // namespace internal
596 
597 template <typename T> bool RoundToLong(T x, long &result) {
598   MPFRNumber mpfr(x);
599   return mpfr.roundToLong(result);
600 }
601 
602 template bool RoundToLong<float>(float, long &);
603 template bool RoundToLong<double>(double, long &);
604 template bool RoundToLong<long double>(long double, long &);
605 
606 template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result) {
607   MPFRNumber mpfr(x);
608   return mpfr.roundToLong(internal::getMPFRRoundingMode(mode), result);
609 }
610 
611 template bool RoundToLong<float>(float, RoundingMode, long &);
612 template bool RoundToLong<double>(double, RoundingMode, long &);
613 template bool RoundToLong<long double>(long double, RoundingMode, long &);
614 
615 template <typename T> T Round(T x, RoundingMode mode) {
616   MPFRNumber mpfr(x);
617   MPFRNumber result = mpfr.rint(internal::getMPFRRoundingMode(mode));
618   return result.as<T>();
619 }
620 
621 template float Round<float>(float, RoundingMode);
622 template double Round<double>(double, RoundingMode);
623 template long double Round<long double>(long double, RoundingMode);
624 
625 } // namespace mpfr
626 } // namespace testing
627 } // namespace __llvm_libc
628