googletest icon indicating copy to clipboard operation
googletest copied to clipboard

Floating-point values not printed with enough precision

Open pitrou opened this issue 5 years ago • 8 comments

I recently had this failure on a CI platform:

C:/projects/arrow/cpp/src/arrow/util/decimal_test.cc(557): error: Expected equality of these values:
  dec.ToReal<Real>(scale)
    Which is: 1e-163
  expected
    Which is: 1e-163

Needless to say, this is not very informative :-) Floating-point values should be printed with enough precision to recreate the exact same values from the string representation, so as to diagnose issues.

pitrou avatar Jul 02 '20 16:07 pitrou

If the values were printed as hexfloat as well, the issue would be moot:

C:/projects/arrow/cpp/src/arrow/util/decimal_test.cc(557): error: Expected equality of these values:
  dec.ToReal<Real>(scale)
    Which is: 1e-163 = 0x1.708d0f84d3de7p-542
  expected
    Which is: 1e-163 = 0x1.708d0f84d3defp-542

NAThompson avatar Mar 10 '23 18:03 NAThompson

I'm sorry ,but I don't know how to fix this issue.

maryfranharper avatar Mar 10 '23 18:03 maryfranharper

Here's a solution I once used when a test was strangely failing with values that "seemed" the same (at least according to the EXPECT_EQ() failure printout). I wasn't working with values as tiny as 1e-163 (and I was also working with 32-bit float, not double), but the default EXPECT_EQ() behavior wasn't very helpful, as you can see in my comment...

/* Implement a CUSTOM_EXPECT_EQ macro instead of GoogleTest's standard EXPECT_EQ in order to print more digits for
 * floating point failures. E.g. For this EXPECT_EQ(expectedResult, m_measData.voltage[ePhaseA]) failure...
 *              Expected equality of these values:
 *                expectedResult
 *                  Which is: 0.0726339
 *                m_measData.voltage[ePhaseA]
 *                  Which is: 0.0726339
 * ...(note that expected & actual are rounded and appear the same!), with CUSTOM_EXPECT_EQ, we would see this instead:
 *              Expected equality of these values:
 *                expectedResult
 *                  Which is: 0.072633899748325348
 *                m_measData.voltage[ePhaseA]
 *                  Which is: 0.072633907198905945
 */
#define CUSTOM_EXPECT_EQ(expected,actual) EXPECT_PRED_FORMAT2(floatEqPred, expected, actual)
testing::AssertionResult floatEqPred(char const* expectedFmt, char const* actualFmt, float32_t expected, float32_t actual)
{
   return (expected == actual)
      ? testing::AssertionSuccess()
      : testing::AssertionFailure() << "Expected equality of these values:\n  "
              << expectedFmt << "\n    Which is: " << expected << "\n  "
              << actualFmt << "\n    Which is: " << actual << "\n";
}

phonetagger avatar Mar 10 '23 18:03 phonetagger

@phonetagger: Yup, the only robust solution here is hexfloat printing.

NAThompson avatar Mar 10 '23 19:03 NAThompson

@NAThompson Are you saying there's no robust solution that prints floating point values in easy-to-interpret decimal? Most people wouldn't be happy to have to convert from hexfloat to a format they can actually work with.

phonetagger avatar Mar 10 '23 20:03 phonetagger

AFAIK, printing with enough precision is implemented by a bunch of open source libraries, including Google's own double-precision.

pitrou avatar Mar 10 '23 20:03 pitrou

Most people wouldn't be happy to have to convert from hexfloat to a format they can actually work with.

Just print both formats.

NAThompson avatar Mar 10 '23 20:03 NAThompson

Diff to fix:

diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index 04a84f32..02fb4d36 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -1572,11 +1572,11 @@ AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,

   ::std::stringstream lhs_ss;
   lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
-         << lhs_value;
+         << lhs_value << " = " << std::hexfloat << lhs_value;

   ::std::stringstream rhs_ss;
   rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
-         << rhs_value;
+         << rhs_value << " = " << std::hexfloat << lhs_value;

   return EqFailure(lhs_expression, rhs_expression,
                    StringStreamToString(&lhs_ss), StringStreamToString(&rhs_ss),

NAThompson avatar Mar 11 '23 03:03 NAThompson