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