diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -47,7 +47,7 @@ // input and produce a single floating point number of the same type as // output. BeginBinaryOperationsSingleOutput, - // TODO: Add operations like hypot. + Hypot, EndBinaryOperationsSingleOutput, // Operations which take two floating point numbers of the same type as @@ -109,6 +109,10 @@ const BinaryOutput &libcOutput, double t); +template +bool compareBinaryOperationOneOutput(Operation op, const BinaryInput &input, + T libcOutput, double t); + template void explainUnaryOperationSingleOutputError(Operation op, T input, T matchValue, testutils::StreamWrapper &OS); @@ -122,6 +126,12 @@ const BinaryOutput &matchValue, testutils::StreamWrapper &OS); +template +void explainBinaryOperationOneOutputError(Operation op, + const BinaryInput &input, + T matchValue, + testutils::StreamWrapper &OS); + template class MPFRMatcher : public testing::Matcher { InputType input; @@ -153,7 +163,7 @@ template static bool match(const BinaryInput &in, T out, double tolerance) { - // TODO: Implement the comparision function and error reporter. + return compareBinaryOperationOneOutput(op, in, out, tolerance); } template @@ -183,6 +193,12 @@ testutils::StreamWrapper &OS) { explainBinaryOperationTwoOutputsError(op, in, out, OS); } + + template + static void explainError(const BinaryInput &in, T out, + testutils::StreamWrapper &OS) { + explainBinaryOperationOneOutputError(op, in, out, OS); + } }; } // namespace internal diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -133,6 +133,12 @@ return result; } + MPFRNumber hypot(const MPFRNumber &b) { + MPFRNumber result; + mpfr_hypot(result.value, value, b.value, MPFR_RNDN); + return result; + } + MPFRNumber remquo(const MPFRNumber &divisor, int "ient) { MPFRNumber remainder; long q; @@ -276,6 +282,18 @@ } } +template +cpp::EnableIfType::Value, MPFRNumber> +binaryOperationOneOutput(Operation op, InputType x, InputType y) { + MPFRNumber inputX(x), inputY(y); + switch (op) { + case Operation::Hypot: + return inputX.hypot(inputY); + default: + __builtin_unreachable(); + } +} + template cpp::EnableIfType::Value, MPFRNumber> binaryOperationTwoOutputs(Operation op, InputType x, InputType y, int &output) { @@ -401,6 +419,41 @@ Operation, const BinaryInput &, const BinaryOutput &, testutils::StreamWrapper &); +template +void explainBinaryOperationOneOutputError(Operation op, + const BinaryInput &input, + T libcResult, + testutils::StreamWrapper &OS) { + MPFRNumber mpfrX(input.x); + MPFRNumber mpfrY(input.y); + FPBits xbits(input.x); + FPBits ybits(input.y); + MPFRNumber mpfrResult = binaryOperationOneOutput(op, input.x, input.y); + MPFRNumber mpfrMatchValue(libcResult); + + OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'; + __llvm_libc::fputil::testing::describeValue("First input bits: ", input.x, + OS); + __llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y, + OS); + + OS << "Libc result: " << mpfrMatchValue.str() << '\n' + << "MPFR result: " << mpfrResult.str() << '\n'; + __llvm_libc::fputil::testing::describeValue( + "Libc floating point result bits: ", libcResult, OS); + __llvm_libc::fputil::testing::describeValue( + " MPFR rounded bits: ", mpfrResult.as(), OS); + OS << "ULP error: " << std::to_string(mpfrResult.ulp(libcResult)) << '\n'; +} + +template void explainBinaryOperationOneOutputError( + Operation, const BinaryInput &, float, testutils::StreamWrapper &); +template void explainBinaryOperationOneOutputError( + Operation, const BinaryInput &, double, testutils::StreamWrapper &); +template void explainBinaryOperationOneOutputError( + Operation, const BinaryInput &, long double, + testutils::StreamWrapper &); + template bool compareUnaryOperationSingleOutput(Operation op, T input, T libcResult, double ulpError) { @@ -480,6 +533,26 @@ Operation, const BinaryInput &, const BinaryOutput &, double); +template +bool compareBinaryOperationOneOutput(Operation op, const BinaryInput &input, + T libcResult, double ulpError) { + MPFRNumber mpfrResult = binaryOperationOneOutput(op, input.x, input.y); + double ulp = mpfrResult.ulp(libcResult); + + bool bitsAreEven = ((FPBits(libcResult).bitsAsUInt() & 1) == 0); + return (ulp < ulpError) || + ((ulp == ulpError) && ((ulp != 0.5) || bitsAreEven)); +} + +template bool compareBinaryOperationOneOutput(Operation, + const BinaryInput &, + float, double); +template bool +compareBinaryOperationOneOutput(Operation, const BinaryInput &, + double, double); +template bool compareBinaryOperationOneOutput( + Operation, const BinaryInput &, long double, double); + } // namespace internal } // namespace mpfr