89 changes: 52 additions & 37 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <cmath>
#include <fenv.h>
#include <memory>
#include <sstream>
#include <stdint.h>
#include <string>

Expand Down Expand Up @@ -571,6 +572,10 @@ ternary_operation_one_output(Operation op, InputType x, InputType y,
}
}

// Remark: For all the explain_*_error functions, we will use std::stringstream
// to build the complete error messages before sending it to the outstream `OS`
// once at the end. This will stop the error messages from interleaving when
// the tests are running concurrently.
template <typename T>
void explain_unary_operation_single_output_error(Operation op, T input,
T matchValue,
Expand All @@ -582,18 +587,20 @@ void explain_unary_operation_single_output_error(Operation op, T input,
MPFRNumber mpfr_result;
mpfr_result = unary_operation(op, input, precision, rounding);
MPFRNumber mpfrMatchValue(matchValue);
OS << "Match value not within tolerance value of MPFR result:\n"
std::stringstream ss;
ss << "Match value not within tolerance value of MPFR result:\n"
<< " Input decimal: " << mpfrInput.str() << '\n';
__llvm_libc::fputil::testing::describeValue(" Input bits: ", input, OS);
OS << '\n' << " Match decimal: " << mpfrMatchValue.str() << '\n';
__llvm_libc::fputil::testing::describeValue(" Input bits: ", input, ss);
ss << '\n' << " Match decimal: " << mpfrMatchValue.str() << '\n';
__llvm_libc::fputil::testing::describeValue(" Match bits: ", matchValue,
OS);
OS << '\n' << " MPFR result: " << mpfr_result.str() << '\n';
ss);
ss << '\n' << " MPFR result: " << mpfr_result.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded: ", mpfr_result.as<T>(), OS);
OS << '\n';
OS << " ULP error: " << std::to_string(mpfr_result.ulp(matchValue))
" MPFR rounded: ", mpfr_result.as<T>(), ss);
ss << '\n';
ss << " ULP error: " << std::to_string(mpfr_result.ulp(matchValue))
<< '\n';
OS << ss.str();
}

template void
Expand All @@ -616,31 +623,33 @@ void explain_unary_operation_two_outputs_error(
int mpfrIntResult;
MPFRNumber mpfr_result = unary_operation_two_outputs(op, input, mpfrIntResult,
precision, rounding);
std::stringstream ss;

if (mpfrIntResult != libc_result.i) {
OS << "MPFR integral result: " << mpfrIntResult << '\n'
ss << "MPFR integral result: " << mpfrIntResult << '\n'
<< "Libc integral result: " << libc_result.i << '\n';
} else {
OS << "Integral result from libc matches integral result from MPFR.\n";
ss << "Integral result from libc matches integral result from MPFR.\n";
}

MPFRNumber mpfrMatchValue(libc_result.f);
OS << "Libc floating point result is not within tolerance value of the MPFR "
ss << "Libc floating point result is not within tolerance value of the MPFR "
<< "result.\n\n";

OS << " Input decimal: " << mpfrInput.str() << "\n\n";
ss << " Input decimal: " << mpfrInput.str() << "\n\n";

OS << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
ss << "Libc floating point value: " << mpfrMatchValue.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
" Libc floating point bits: ", libc_result.f, OS);
OS << "\n\n";
" Libc floating point bits: ", libc_result.f, ss);
ss << "\n\n";

OS << " MPFR result: " << mpfr_result.str() << '\n';
ss << " MPFR result: " << mpfr_result.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded: ", mpfr_result.as<T>(), OS);
OS << '\n'
" MPFR rounded: ", mpfr_result.as<T>(), ss);
ss << '\n'
<< " ULP error: "
<< std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
OS << ss.str();
}

template void explain_unary_operation_two_outputs_error<float>(
Expand All @@ -665,17 +674,19 @@ void explain_binary_operation_two_outputs_error(
MPFRNumber mpfr_result = binary_operation_two_outputs(
op, input.x, input.y, mpfrIntResult, precision, rounding);
MPFRNumber mpfrMatchValue(libc_result.f);
std::stringstream ss;

OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'
<< "MPFR integral result: " << mpfrIntResult << '\n'
<< "Libc integral result: " << libc_result.i << '\n'
<< "Libc floating point result: " << mpfrMatchValue.str() << '\n'
<< " MPFR result: " << mpfr_result.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
"Libc floating point result bits: ", libc_result.f, OS);
"Libc floating point result bits: ", libc_result.f, ss);
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded bits: ", mpfr_result.as<T>(), OS);
OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
" MPFR rounded bits: ", mpfr_result.as<T>(), ss);
ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result.f)) << '\n';
OS << ss.str();
}

template void explain_binary_operation_two_outputs_error<float>(
Expand All @@ -701,20 +712,22 @@ void explain_binary_operation_one_output_error(
MPFRNumber mpfr_result =
binary_operation_one_output(op, input.x, input.y, precision, rounding);
MPFRNumber mpfrMatchValue(libc_result);
std::stringstream ss;

OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n';
__llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
OS);
ss);
__llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
OS);
ss);

OS << "Libc result: " << mpfrMatchValue.str() << '\n'
ss << "Libc result: " << mpfrMatchValue.str() << '\n'
<< "MPFR result: " << mpfr_result.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
"Libc floating point result bits: ", libc_result, OS);
"Libc floating point result bits: ", libc_result, ss);
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded bits: ", mpfr_result.as<T>(), OS);
OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
" MPFR rounded bits: ", mpfr_result.as<T>(), ss);
ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
OS << ss.str();
}

template void explain_binary_operation_one_output_error<float>(
Expand All @@ -741,23 +754,25 @@ void explain_ternary_operation_one_output_error(
MPFRNumber mpfr_result = ternary_operation_one_output(
op, input.x, input.y, input.z, precision, rounding);
MPFRNumber mpfrMatchValue(libc_result);
std::stringstream ss;

OS << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
ss << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str()
<< " z: " << mpfrZ.str() << '\n';
__llvm_libc::fputil::testing::describeValue("First input bits: ", input.x,
OS);
ss);
__llvm_libc::fputil::testing::describeValue("Second input bits: ", input.y,
OS);
ss);
__llvm_libc::fputil::testing::describeValue("Third input bits: ", input.z,
OS);
ss);

OS << "Libc result: " << mpfrMatchValue.str() << '\n'
ss << "Libc result: " << mpfrMatchValue.str() << '\n'
<< "MPFR result: " << mpfr_result.str() << '\n';
__llvm_libc::fputil::testing::describeValue(
"Libc floating point result bits: ", libc_result, OS);
"Libc floating point result bits: ", libc_result, ss);
__llvm_libc::fputil::testing::describeValue(
" MPFR rounded bits: ", mpfr_result.as<T>(), OS);
OS << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
" MPFR rounded bits: ", mpfr_result.as<T>(), ss);
ss << "ULP error: " << std::to_string(mpfr_result.ulp(libc_result)) << '\n';
OS << ss.str();
}

template void explain_ternary_operation_one_output_error<float>(
Expand Down
25 changes: 17 additions & 8 deletions libc/utils/UnitTest/FPMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "src/__support/FPUtil/FPBits.h"

#include <sstream>
#include <string>

namespace __llvm_libc {
Expand All @@ -30,10 +31,9 @@ uintToHex(T X, size_t Length = sizeof(T) * 2) {
return s;
}

template <typename ValType>
template <typename ValType, typename StreamType>
cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, void>
describeValue(const char *label, ValType value,
testutils::StreamWrapper &stream) {
describeValue(const char *label, ValType value, StreamType &stream) {
stream << label;

FPBits<ValType> bits(value);
Expand All @@ -49,15 +49,19 @@ describeValue(const char *label, ValType value,
(fputil::ExponentWidth<ValType>::VALUE - 1) / 4 + 1;
constexpr int mantissaWidthInHex =
(fputil::MantissaWidth<ValType>::VALUE - 1) / 4 + 1;
constexpr int bitsWidthInHex =
sizeof(typename fputil::FPBits<ValType>::UIntType) * 2;

stream << "Sign: " << (bits.get_sign() ? '1' : '0') << ", "
<< "Exponent: 0x"
stream << "0x"
<< uintToHex<typename fputil::FPBits<ValType>::UIntType>(
bits.uintval(), bitsWidthInHex)
<< ", (S | E | M) = (" << (bits.get_sign() ? '1' : '0') << " | 0x"
<< uintToHex<uint16_t>(bits.get_unbiased_exponent(),
exponentWidthInHex)
<< ", "
<< "Mantissa: 0x"
<< " | 0x"
<< uintToHex<typename fputil::FPBits<ValType>::UIntType>(
bits.get_mantissa(), mantissaWidthInHex);
bits.get_mantissa(), mantissaWidthInHex)
<< ")";
}

stream << '\n';
Expand All @@ -70,6 +74,11 @@ template void describeValue<double>(const char *, double,
template void describeValue<long double>(const char *, long double,
testutils::StreamWrapper &);

template void describeValue<float>(const char *, float, std::stringstream &);
template void describeValue<double>(const char *, double, std::stringstream &);
template void describeValue<long double>(const char *, long double,
std::stringstream &);

} // namespace testing
} // namespace fputil
} // namespace __llvm_libc
5 changes: 2 additions & 3 deletions libc/utils/UnitTest/FPMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ namespace __llvm_libc {
namespace fputil {
namespace testing {

template <typename ValType>
template <typename ValType, typename StreamType>
cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, void>
describeValue(const char *label, ValType value,
testutils::StreamWrapper &stream);
describeValue(const char *label, ValType value, StreamType &stream);

template <typename T, __llvm_libc::testing::TestCondition Condition>
class FPMatcher : public __llvm_libc::testing::Matcher<T> {
Expand Down