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#include "MPCommon.h"
11
12#include "src/__support/CPP/array.h"
13#include "src/__support/CPP/stringstream.h"
14#include "src/__support/FPUtil/fpbits_str.h"
15#include "src/__support/macros/config.h"
16#include "src/__support/macros/properties/types.h"
17
18namespace LIBC_NAMESPACE_DECL {
19namespace testing {
20namespace mpfr {
21namespace internal {
22
23template <typename InputType>
24cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
25unary_operation(Operation op, InputType input, unsigned int precision,
26 RoundingMode rounding) {
27 MPFRNumber mpfrInput(input, precision, rounding);
28 switch (op) {
29 case Operation::Abs:
30 return mpfrInput.abs();
31 case Operation::Acos:
32 return mpfrInput.acos();
33 case Operation::Acosh:
34 return mpfrInput.acosh();
35 case Operation::Acospi:
36 return mpfrInput.acospi();
37 case Operation::Asin:
38 return mpfrInput.asin();
39 case Operation::Asinh:
40 return mpfrInput.asinh();
41 case Operation::Atan:
42 return mpfrInput.atan();
43 case Operation::Atanh:
44 return mpfrInput.atanh();
45 case Operation::Cbrt:
46 return mpfrInput.cbrt();
47 case Operation::Ceil:
48 return mpfrInput.ceil();
49 case Operation::Cos:
50 return mpfrInput.cos();
51 case Operation::Cosh:
52 return mpfrInput.cosh();
53 case Operation::Cospi:
54 return mpfrInput.cospi();
55 case Operation::Erf:
56 return mpfrInput.erf();
57 case Operation::Exp:
58 return mpfrInput.exp();
59 case Operation::Exp2:
60 return mpfrInput.exp2();
61 case Operation::Exp2m1:
62 return mpfrInput.exp2m1();
63 case Operation::Exp10:
64 return mpfrInput.exp10();
65 case Operation::Exp10m1:
66 return mpfrInput.exp10m1();
67 case Operation::Expm1:
68 return mpfrInput.expm1();
69 case Operation::Floor:
70 return mpfrInput.floor();
71 case Operation::Log:
72 return mpfrInput.log();
73 case Operation::Log2:
74 return mpfrInput.log2();
75 case Operation::Log10:
76 return mpfrInput.log10();
77 case Operation::Log1p:
78 return mpfrInput.log1p();
79 case Operation::Mod2PI:
80 return mpfrInput.mod_2pi();
81 case Operation::ModPIOver2:
82 return mpfrInput.mod_pi_over_2();
83 case Operation::ModPIOver4:
84 return mpfrInput.mod_pi_over_4();
85 case Operation::Round:
86 return mpfrInput.round();
87 case Operation::RoundEven:
88 return mpfrInput.roundeven();
89 case Operation::Sin:
90 return mpfrInput.sin();
91 case Operation::Sinpi:
92 return mpfrInput.sinpi();
93 case Operation::Sinh:
94 return mpfrInput.sinh();
95 case Operation::Sqrt:
96 return mpfrInput.sqrt();
97 case Operation::Tan:
98 return mpfrInput.tan();
99 case Operation::Tanh:
100 return mpfrInput.tanh();
101 case Operation::Tanpi:
102 return mpfrInput.tanpi();
103 case Operation::Trunc:
104 return mpfrInput.trunc();
105 default:
106 __builtin_unreachable();
107 }
108}
109
110template <typename InputType>
111cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
112unary_operation_two_outputs(Operation op, InputType input, int &output,
113 unsigned int precision, RoundingMode rounding) {
114 MPFRNumber mpfrInput(input, precision, rounding);
115 switch (op) {
116 case Operation::Frexp:
117 return mpfrInput.frexp(output);
118 default:
119 __builtin_unreachable();
120 }
121}
122
123template <typename InputType>
124cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
125binary_operation_one_output(Operation op, InputType x, InputType y,
126 unsigned int precision, RoundingMode rounding) {
127 MPFRNumber inputX(x, precision, rounding);
128 MPFRNumber inputY(y, precision, rounding);
129 switch (op) {
130 case Operation::Add:
131 return inputX.add(inputY);
132 case Operation::Atan2:
133 return inputX.atan2(inputY);
134 case Operation::Div:
135 return inputX.div(inputY);
136 case Operation::Fmod:
137 return inputX.fmod(inputY);
138 case Operation::Hypot:
139 return inputX.hypot(inputY);
140 case Operation::Mul:
141 return inputX.mul(inputY);
142 case Operation::Pow:
143 return inputX.pow(inputY);
144 case Operation::Sub:
145 return inputX.sub(inputY);
146 default:
147 __builtin_unreachable();
148 }
149}
150
151template <typename InputType>
152cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
153binary_operation_two_outputs(Operation op, InputType x, InputType y,
154 int &output, unsigned int precision,
155 RoundingMode rounding) {
156 MPFRNumber inputX(x, precision, rounding);
157 MPFRNumber inputY(y, precision, rounding);
158 switch (op) {
159 case Operation::RemQuo:
160 return inputX.remquo(inputY, output);
161 default:
162 __builtin_unreachable();
163 }
164}
165
166template <typename InputType>
167cpp::enable_if_t<cpp::is_floating_point_v<InputType>, MPFRNumber>
168ternary_operation_one_output(Operation op, InputType x, InputType y,
169 InputType z, unsigned int precision,
170 RoundingMode rounding) {
171 // For FMA function, we just need to compare with the mpfr_fma with the same
172 // precision as InputType. Using higher precision as the intermediate results
173 // to compare might incorrectly fail due to double-rounding errors.
174 MPFRNumber inputX(x, precision, rounding);
175 MPFRNumber inputY(y, precision, rounding);
176 MPFRNumber inputZ(z, precision, rounding);
177 switch (op) {
178 case Operation::Fma:
179 return inputX.fma(inputY, inputZ);
180 default:
181 __builtin_unreachable();
182 }
183}
184
185// Remark: For all the explain_*_error functions, we will use std::stringstream
186// to build the complete error messages before sending it to the outstream `OS`
187// once at the end. This will stop the error messages from interleaving when
188// the tests are running concurrently.
189template <typename InputType, typename OutputType>
190void explain_unary_operation_single_output_error(Operation op, InputType input,
191 OutputType matchValue,
192 double ulp_tolerance,
193 RoundingMode rounding) {
194 unsigned int precision = get_precision<InputType>(ulp_tolerance);
195 MPFRNumber mpfrInput(input, precision);
196 MPFRNumber mpfr_result;
197 mpfr_result = unary_operation(op, input, precision, rounding);
198 MPFRNumber mpfrMatchValue(matchValue);
199 cpp::array<char, 1024> msg_buf;
200 cpp::StringStream msg(msg_buf);
201 msg << "Match value not within tolerance value of MPFR result:\n"
202 << " Input decimal: " << mpfrInput.str() << '\n';
203 msg << " Input bits: " << str(FPBits<InputType>(input)) << '\n';
204 msg << '\n' << " Match decimal: " << mpfrMatchValue.str() << '\n';
205 msg << " Match bits: " << str(FPBits<OutputType>(matchValue)) << '\n';
206 msg << '\n' << " MPFR result: " << mpfr_result.str() << '\n';
207 msg << " MPFR rounded: "
208 << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
209 msg << '\n';
210 msg << " ULP error: " << mpfr_result.ulp_as_mpfr_number(matchValue).str()
211 << '\n';
212 if (msg.overflow())
213 __builtin_unreachable();
214 tlog << msg.str();
215}
216
217template void explain_unary_operation_single_output_error(Operation op, float,
218 float, double,
219 RoundingMode);
220template void explain_unary_operation_single_output_error(Operation op, double,
221 double, double,
222 RoundingMode);
223template void explain_unary_operation_single_output_error(Operation op,
224 long double,
225 long double, double,
226 RoundingMode);
227template void explain_unary_operation_single_output_error(Operation op, double,
228 float, double,
229 RoundingMode);
230template void explain_unary_operation_single_output_error(Operation op,
231 long double, float,
232 double, RoundingMode);
233template void explain_unary_operation_single_output_error(Operation op,
234 long double, double,
235 double, RoundingMode);
236
237#ifdef LIBC_TYPES_HAS_FLOAT16
238template void explain_unary_operation_single_output_error(Operation op, float16,
239 float16, double,
240 RoundingMode);
241template void explain_unary_operation_single_output_error(Operation op, float,
242 float16, double,
243 RoundingMode);
244template void explain_unary_operation_single_output_error(Operation op, double,
245 float16, double,
246 RoundingMode);
247template void explain_unary_operation_single_output_error(Operation op,
248 long double, float16,
249 double, RoundingMode);
250#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
251template void explain_unary_operation_single_output_error(Operation op,
252 float128, float16,
253 double, RoundingMode);
254#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
255#endif // LIBC_TYPES_HAS_FLOAT16
256
257#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
258template void explain_unary_operation_single_output_error(Operation op,
259 float128, float128,
260 double, RoundingMode);
261template void explain_unary_operation_single_output_error(Operation op,
262 float128, float,
263 double, RoundingMode);
264template void explain_unary_operation_single_output_error(Operation op,
265 float128, double,
266 double, RoundingMode);
267template void explain_unary_operation_single_output_error(Operation op,
268 float128, long double,
269 double, RoundingMode);
270#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
271
272template <typename T>
273void explain_unary_operation_two_outputs_error(
274 Operation op, T input, const BinaryOutput<T> &libc_result,
275 double ulp_tolerance, RoundingMode rounding) {
276 unsigned int precision = get_precision<T>(ulp_tolerance);
277 MPFRNumber mpfrInput(input, precision);
278 int mpfrIntResult;
279 MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
280 precision, rounding);
281
282 if (mpfrIntResult != libc_result.i) {
283 tlog << "MPFR integral result: " << mpfrIntResult << '\n'
284 << "Libc integral result: " << libc_result.i << '\n';
285 } else {
286 tlog << "Integral result from libc matches integral result from MPFR.\n";
287 }
288
289 MPFRNumber mpfrMatchValue(libc_result.f);
290 tlog
291 << "Libc floating point result is not within tolerance value of the MPFR "
292 << "result.\n\n";
293
294 tlog << " Input decimal: " << mpfrInput.str() << "\n\n";
295
296 tlog << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
297 tlog << " Libc floating point bits: " << str(FPBits<T>(libc_result.f))
298 << '\n';
299 tlog << "\n\n";
300
301 tlog << " MPFR result: " << mpfr_result.str() << '\n';
302 tlog << " MPFR rounded: " << str(FPBits<T>(mpfr_result.as<T>()))
303 << '\n';
304 tlog << '\n'
305 << " ULP error: "
306 << mpfr_result.ulp_as_mpfr_number(libc_result.f).str() << '\n';
307}
308
309template void explain_unary_operation_two_outputs_error<float>(
310 Operation, float, const BinaryOutput<float> &, double, RoundingMode);
311template void explain_unary_operation_two_outputs_error<double>(
312 Operation, double, const BinaryOutput<double> &, double, RoundingMode);
313template void explain_unary_operation_two_outputs_error<long double>(
314 Operation, long double, const BinaryOutput<long double> &, double,
315 RoundingMode);
316
317template <typename T>
318void explain_binary_operation_two_outputs_error(
319 Operation op, const BinaryInput<T> &input,
320 const BinaryOutput<T> &libc_result, double ulp_tolerance,
321 RoundingMode rounding) {
322 unsigned int precision = get_precision<T>(ulp_tolerance);
323 MPFRNumber mpfrX(input.x, precision);
324 MPFRNumber mpfrY(input.y, precision);
325 int mpfrIntResult;
326 MPFRNumber mpfr_result = binary_operation_two_outputs(
327 op, input.x, input.y, mpfrIntResult, precision, rounding);
328 MPFRNumber mpfrMatchValue(libc_result.f);
329
330 tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
331 << "MPFR integral result: " << mpfrIntResult << '\n'
332 << "Libc integral result: " << libc_result.i << '\n'
333 << "Libc floating point result: " << mpfrMatchValue.str() << '\n'
334 << " MPFR result: " << mpfr_result.str() << '\n';
335 tlog << "Libc floating point result bits: " << str(FPBits<T>(libc_result.f))
336 << '\n';
337 tlog << " MPFR rounded bits: "
338 << str(FPBits<T>(mpfr_result.as<T>())) << '\n';
339 tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result.f).str()
340 << '\n';
341}
342
343template void explain_binary_operation_two_outputs_error<float>(
344 Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
345 RoundingMode);
346template void explain_binary_operation_two_outputs_error<double>(
347 Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
348 double, RoundingMode);
349template void explain_binary_operation_two_outputs_error<long double>(
350 Operation, const BinaryInput<long double> &,
351 const BinaryOutput<long double> &, double, RoundingMode);
352
353template <typename InputType, typename OutputType>
354void explain_binary_operation_one_output_error(
355 Operation op, const BinaryInput<InputType> &input, OutputType libc_result,
356 double ulp_tolerance, RoundingMode rounding) {
357 unsigned int precision = get_precision<InputType>(ulp_tolerance);
358 MPFRNumber mpfrX(input.x, precision);
359 MPFRNumber mpfrY(input.y, precision);
360 FPBits<InputType> xbits(input.x);
361 FPBits<InputType> ybits(input.y);
362 MPFRNumber mpfr_result =
363 binary_operation_one_output(op, input.x, input.y, precision, rounding);
364 MPFRNumber mpfrMatchValue(libc_result);
365
366 tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
367 tlog << "First input bits: " << str(FPBits<InputType>(input.x)) << '\n';
368 tlog << "Second input bits: " << str(FPBits<InputType>(input.y)) << '\n';
369
370 tlog << "Libc result: " << mpfrMatchValue.str() << '\n'
371 << "MPFR result: " << mpfr_result.str() << '\n';
372 tlog << "Libc floating point result bits: "
373 << str(FPBits<OutputType>(libc_result)) << '\n';
374 tlog << " MPFR rounded bits: "
375 << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
376 tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str()
377 << '\n';
378}
379
380template void
381explain_binary_operation_one_output_error(Operation, const BinaryInput<float> &,
382 float, double, RoundingMode);
383template void explain_binary_operation_one_output_error(
384 Operation, const BinaryInput<double> &, float, double, RoundingMode);
385template void explain_binary_operation_one_output_error(
386 Operation, const BinaryInput<double> &, double, double, RoundingMode);
387template void explain_binary_operation_one_output_error(
388 Operation, const BinaryInput<long double> &, float, double, RoundingMode);
389template void explain_binary_operation_one_output_error(
390 Operation, const BinaryInput<long double> &, double, double, RoundingMode);
391template void
392explain_binary_operation_one_output_error(Operation,
393 const BinaryInput<long double> &,
394 long double, double, RoundingMode);
395#ifdef LIBC_TYPES_HAS_FLOAT16
396template void explain_binary_operation_one_output_error(
397 Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
398template void
399explain_binary_operation_one_output_error(Operation, const BinaryInput<float> &,
400 float16, double, RoundingMode);
401template void explain_binary_operation_one_output_error(
402 Operation, const BinaryInput<double> &, float16, double, RoundingMode);
403template void explain_binary_operation_one_output_error(
404 Operation, const BinaryInput<long double> &, float16, double, RoundingMode);
405#endif
406#if defined(LIBC_TYPES_HAS_FLOAT128) && \
407 defined(LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE)
408template void explain_binary_operation_one_output_error(
409 Operation, const BinaryInput<float128> &, float128, double, RoundingMode);
410#endif
411
412template <typename InputType, typename OutputType>
413void explain_ternary_operation_one_output_error(
414 Operation op, const TernaryInput<InputType> &input, OutputType libc_result,
415 double ulp_tolerance, RoundingMode rounding) {
416 unsigned int precision = get_precision<InputType>(ulp_tolerance);
417 MPFRNumber mpfrX(input.x, precision);
418 MPFRNumber mpfrY(input.y, precision);
419 MPFRNumber mpfrZ(input.z, precision);
420 FPBits<InputType> xbits(input.x);
421 FPBits<InputType> ybits(input.y);
422 FPBits<InputType> zbits(input.z);
423 MPFRNumber mpfr_result = ternary_operation_one_output(
424 op, input.x, input.y, input.z, precision, rounding);
425 MPFRNumber mpfrMatchValue(libc_result);
426
427 tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
428 << " z: " << mpfrZ.str() << '\n';
429 tlog << " First input bits: " << str(FPBits<InputType>(input.x)) << '\n';
430 tlog << "Second input bits: " << str(FPBits<InputType>(input.y)) << '\n';
431 tlog << " Third input bits: " << str(FPBits<InputType>(input.z)) << '\n';
432
433 tlog << "Libc result: " << mpfrMatchValue.str() << '\n'
434 << "MPFR result: " << mpfr_result.str() << '\n';
435 tlog << "Libc floating point result bits: "
436 << str(FPBits<OutputType>(libc_result)) << '\n';
437 tlog << " MPFR rounded bits: "
438 << str(FPBits<OutputType>(mpfr_result.as<OutputType>())) << '\n';
439 tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str()
440 << '\n';
441}
442
443template void explain_ternary_operation_one_output_error(
444 Operation, const TernaryInput<float> &, float, double, RoundingMode);
445template void explain_ternary_operation_one_output_error(
446 Operation, const TernaryInput<double> &, float, double, RoundingMode);
447template void explain_ternary_operation_one_output_error(
448 Operation, const TernaryInput<double> &, double, double, RoundingMode);
449template void explain_ternary_operation_one_output_error(
450 Operation, const TernaryInput<long double> &, float, double, RoundingMode);
451template void explain_ternary_operation_one_output_error(
452 Operation, const TernaryInput<long double> &, double, double, RoundingMode);
453template void
454explain_ternary_operation_one_output_error(Operation,
455 const TernaryInput<long double> &,
456 long double, double, RoundingMode);
457
458#ifdef LIBC_TYPES_HAS_FLOAT16
459template void explain_ternary_operation_one_output_error(
460 Operation, const TernaryInput<float16> &, float16, double, RoundingMode);
461template void explain_ternary_operation_one_output_error(
462 Operation, const TernaryInput<float> &, float16, double, RoundingMode);
463template void explain_ternary_operation_one_output_error(
464 Operation, const TernaryInput<double> &, float16, double, RoundingMode);
465template void
466explain_ternary_operation_one_output_error(Operation,
467 const TernaryInput<long double> &,
468 float16, double, RoundingMode);
469#endif
470
471template <typename InputType, typename OutputType>
472bool compare_unary_operation_single_output(Operation op, InputType input,
473 OutputType libc_result,
474 double ulp_tolerance,
475 RoundingMode rounding) {
476 unsigned int precision = get_precision<InputType>(ulp_tolerance);
477 MPFRNumber mpfr_result;
478 mpfr_result = unary_operation(op, input, precision, rounding);
479 double ulp = mpfr_result.ulp(libc_result);
480 return (ulp <= ulp_tolerance);
481}
482
483template bool compare_unary_operation_single_output(Operation, float, float,
484 double, RoundingMode);
485template bool compare_unary_operation_single_output(Operation, double, double,
486 double, RoundingMode);
487template bool compare_unary_operation_single_output(Operation, long double,
488 long double, double,
489 RoundingMode);
490template bool compare_unary_operation_single_output(Operation, double, float,
491 double, RoundingMode);
492template bool compare_unary_operation_single_output(Operation, long double,
493 float, double,
494 RoundingMode);
495template bool compare_unary_operation_single_output(Operation, long double,
496 double, double,
497 RoundingMode);
498#ifdef LIBC_TYPES_HAS_FLOAT16
499template bool compare_unary_operation_single_output(Operation, float16, float16,
500 double, RoundingMode);
501template bool compare_unary_operation_single_output(Operation, float, float16,
502 double, RoundingMode);
503template bool compare_unary_operation_single_output(Operation, double, float16,
504 double, RoundingMode);
505template bool compare_unary_operation_single_output(Operation, long double,
506 float16, double,
507 RoundingMode);
508#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
509template bool compare_unary_operation_single_output(Operation, float128,
510 float16, double,
511 RoundingMode);
512#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
513#endif // LIBC_TYPES_HAS_FLOAT16
514
515#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
516template bool compare_unary_operation_single_output(Operation, float128,
517 float128, double,
518 RoundingMode);
519template bool compare_unary_operation_single_output(Operation, float128, float,
520 double, RoundingMode);
521template bool compare_unary_operation_single_output(Operation, float128, double,
522 double, RoundingMode);
523template bool compare_unary_operation_single_output(Operation, float128,
524 long double, double,
525 RoundingMode);
526#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
527
528template <typename T>
529bool compare_unary_operation_two_outputs(Operation op, T input,
530 const BinaryOutput<T> &libc_result,
531 double ulp_tolerance,
532 RoundingMode rounding) {
533 int mpfrIntResult;
534 unsigned int precision = get_precision<T>(ulp_tolerance);
535 MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
536 precision, rounding);
537 double ulp = mpfr_result.ulp(libc_result.f);
538
539 if (mpfrIntResult != libc_result.i)
540 return false;
541
542 return (ulp <= ulp_tolerance);
543}
544
545template bool compare_unary_operation_two_outputs<float>(
546 Operation, float, const BinaryOutput<float> &, double, RoundingMode);
547template bool compare_unary_operation_two_outputs<double>(
548 Operation, double, const BinaryOutput<double> &, double, RoundingMode);
549template bool compare_unary_operation_two_outputs<long double>(
550 Operation, long double, const BinaryOutput<long double> &, double,
551 RoundingMode);
552
553template <typename T>
554bool compare_binary_operation_two_outputs(Operation op,
555 const BinaryInput<T> &input,
556 const BinaryOutput<T> &libc_result,
557 double ulp_tolerance,
558 RoundingMode rounding) {
559 int mpfrIntResult;
560 unsigned int precision = get_precision<T>(ulp_tolerance);
561 MPFRNumber mpfr_result = binary_operation_two_outputs(
562 op, input.x, input.y, mpfrIntResult, precision, rounding);
563 double ulp = mpfr_result.ulp(libc_result.f);
564
565 if (mpfrIntResult != libc_result.i) {
566 if (op == Operation::RemQuo) {
567 if ((0x7 & mpfrIntResult) != (0x7 & libc_result.i))
568 return false;
569 } else {
570 return false;
571 }
572 }
573
574 return (ulp <= ulp_tolerance);
575}
576
577template bool compare_binary_operation_two_outputs<float>(
578 Operation, const BinaryInput<float> &, const BinaryOutput<float> &, double,
579 RoundingMode);
580template bool compare_binary_operation_two_outputs<double>(
581 Operation, const BinaryInput<double> &, const BinaryOutput<double> &,
582 double, RoundingMode);
583template bool compare_binary_operation_two_outputs<long double>(
584 Operation, const BinaryInput<long double> &,
585 const BinaryOutput<long double> &, double, RoundingMode);
586
587template <typename InputType, typename OutputType>
588bool compare_binary_operation_one_output(Operation op,
589 const BinaryInput<InputType> &input,
590 OutputType libc_result,
591 double ulp_tolerance,
592 RoundingMode rounding) {
593 unsigned int precision = get_precision<InputType>(ulp_tolerance);
594 MPFRNumber mpfr_result =
595 binary_operation_one_output(op, input.x, input.y, precision, rounding);
596 double ulp = mpfr_result.ulp(libc_result);
597
598 return (ulp <= ulp_tolerance);
599}
600
601template bool compare_binary_operation_one_output(Operation,
602 const BinaryInput<float> &,
603 float, double, RoundingMode);
604template bool compare_binary_operation_one_output(Operation,
605 const BinaryInput<double> &,
606 double, double, RoundingMode);
607template bool
608compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
609 float, double, RoundingMode);
610template bool
611compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
612 double, double, RoundingMode);
613template bool
614compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
615 long double, double, RoundingMode);
616
617template bool compare_binary_operation_one_output(Operation,
618 const BinaryInput<double> &,
619 float, double, RoundingMode);
620#ifdef LIBC_TYPES_HAS_FLOAT16
621template bool compare_binary_operation_one_output(Operation,
622 const BinaryInput<float16> &,
623 float16, double,
624 RoundingMode);
625template bool compare_binary_operation_one_output(Operation,
626 const BinaryInput<float> &,
627 float16, double,
628 RoundingMode);
629template bool compare_binary_operation_one_output(Operation,
630 const BinaryInput<double> &,
631 float16, double,
632 RoundingMode);
633template bool
634compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
635 float16, double, RoundingMode);
636#endif
637#if defined(LIBC_TYPES_HAS_FLOAT128) && \
638 defined(LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE)
639template bool compare_binary_operation_one_output(Operation,
640 const BinaryInput<float128> &,
641 float128, double,
642 RoundingMode);
643#endif
644
645template <typename InputType, typename OutputType>
646bool compare_ternary_operation_one_output(Operation op,
647 const TernaryInput<InputType> &input,
648 OutputType libc_result,
649 double ulp_tolerance,
650 RoundingMode rounding) {
651 unsigned int precision = get_precision<InputType>(ulp_tolerance);
652 MPFRNumber mpfr_result = ternary_operation_one_output(
653 op, input.x, input.y, input.z, precision, rounding);
654 double ulp = mpfr_result.ulp(libc_result);
655
656 return (ulp <= ulp_tolerance);
657}
658
659template bool compare_ternary_operation_one_output(Operation,
660 const TernaryInput<float> &,
661 float, double, RoundingMode);
662template bool compare_ternary_operation_one_output(Operation,
663 const TernaryInput<double> &,
664 float, double, RoundingMode);
665template bool compare_ternary_operation_one_output(Operation,
666 const TernaryInput<double> &,
667 double, double,
668 RoundingMode);
669template bool compare_ternary_operation_one_output(
670 Operation, const TernaryInput<long double> &, float, double, RoundingMode);
671template bool compare_ternary_operation_one_output(
672 Operation, const TernaryInput<long double> &, double, double, RoundingMode);
673template bool
674compare_ternary_operation_one_output(Operation,
675 const TernaryInput<long double> &,
676 long double, double, RoundingMode);
677
678#ifdef LIBC_TYPES_HAS_FLOAT16
679template bool
680compare_ternary_operation_one_output(Operation, const TernaryInput<float16> &,
681 float16, double, RoundingMode);
682template bool compare_ternary_operation_one_output(Operation,
683 const TernaryInput<float> &,
684 float16, double,
685 RoundingMode);
686template bool compare_ternary_operation_one_output(Operation,
687 const TernaryInput<double> &,
688 float16, double,
689 RoundingMode);
690template bool
691compare_ternary_operation_one_output(Operation,
692 const TernaryInput<long double> &, float16,
693 double, RoundingMode);
694#endif
695
696} // namespace internal
697
698template <typename T> bool round_to_long(T x, long &result) {
699 MPFRNumber mpfr(x);
700 return mpfr.round_to_long(result);
701}
702
703template bool round_to_long<float>(float, long &);
704template bool round_to_long<double>(double, long &);
705template bool round_to_long<long double>(long double, long &);
706
707#ifdef LIBC_TYPES_HAS_FLOAT16
708template bool round_to_long<float16>(float16, long &);
709#endif // LIBC_TYPES_HAS_FLOAT16
710
711#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
712template bool round_to_long<float128>(float128, long &);
713#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
714
715template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
716 MPFRNumber mpfr(x);
717 return mpfr.round_to_long(get_mpfr_rounding_mode(mode), result);
718}
719
720template bool round_to_long<float>(float, RoundingMode, long &);
721template bool round_to_long<double>(double, RoundingMode, long &);
722template bool round_to_long<long double>(long double, RoundingMode, long &);
723
724#ifdef LIBC_TYPES_HAS_FLOAT16
725template bool round_to_long<float16>(float16, RoundingMode, long &);
726#endif // LIBC_TYPES_HAS_FLOAT16
727
728#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
729template bool round_to_long<float128>(float128, RoundingMode, long &);
730#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
731
732template <typename T> T round(T x, RoundingMode mode) {
733 MPFRNumber mpfr(x);
734 MPFRNumber result = mpfr.rint(get_mpfr_rounding_mode(mode));
735 return result.as<T>();
736}
737
738template float round<float>(float, RoundingMode);
739template double round<double>(double, RoundingMode);
740template long double round<long double>(long double, RoundingMode);
741
742#ifdef LIBC_TYPES_HAS_FLOAT16
743template float16 round<float16>(float16, RoundingMode);
744#endif // LIBC_TYPES_HAS_FLOAT16
745
746#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
747template float128 round<float128>(float128, RoundingMode);
748#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
749
750} // namespace mpfr
751} // namespace testing
752} // namespace LIBC_NAMESPACE_DECL
753

source code of libc/utils/MPFRWrapper/MPFRUtils.cpp