Thread: [Cppunit-devel] assertDoubleEquals, NaN & Microsoft Visual Studio 6
Brought to you by:
blep
From: CppUnit d. m. l. <cpp...@li...> - 2007-02-24 21:13:58
|
The detection of NaN in assertDoubleEquals failed on Microsoft Visual Studio 6. The implementation assumes that NaN != NaN (IEEE-754 says it should). The failure was caused by the way MSVC6 compares floating point number equality: fld qword ptr [nan] fcomp qword ptr [nan] fnstsw ax // copie fp (floating-point) status to register to ax test ah,40h // test bit 14 of ax (0x4000) => C3 of fp status register je $L18438+0B9h (00410be2) According to this doc: http://webster.cs.ucr.edu/AoA/Windows/HTML/RealArithmetic.html#1000117 C2 should be tested for "undefined" value (which I guess NaN fall into). NaN comparison works under visual studio 2005. The equality test is done as follow: fld qword ptr [ebp+10h] fcomp qword ptr [ebp+8] fnstsw ax test ah,44h // Visual Studio 2005 does test both C2 & C3... jp CppUnit::assertDoubleEquals+1B5h (4777A5h) This seems to confirm that MSVC6 code generator is bug (does not respect IEEE-754 standard in spite of what the doc claim). To work-around this, I added an explicit test for NaN value when testing non-finite value for equalities. Here is the function: // To work around this, a NaN is assumed to be detected if no strict ordering is found. inline bool floatingPointIsUnordered( double x ) { // x != x will detect a NaN on conformant platform // (2.0 < x && x < 1.0) will detect a NaN on non conformant platform: // => no ordering can be found for x. return (x != x) || (2.0 < x && x < 1.0); } I'm not an expert on floating-point manipulation & NaN. Does any one see anything wrong on the above implementation or the comments? I modified the defined implementation for isfinite() test to: /// \brief Tests if a floating-point is finite. /// @return \c true if x is neither a NaN, nor +inf, nor -inf, \c false otherwise. inline bool floatingPointIsFinite( double x ) { double testInf = x * 0.0; // Produce 0.0 if x is finite, a NaN otherwise. return testInf == 0.0 && !floatingPointIsUnordered(testInf); } Feedbacks are welcome, Baptiste. --- Baptiste Lepilleur <bl...@us...> CppUnit maintainer OpenTest and CppUnit 2 developer. |
From: CppUnit d. m. l. <cpp...@li...> - 2007-02-25 04:29:44
|
Hi Baptiste, I'm unclear on what problem you are solving here. My guess is that CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, nan, 1.0 ) was passing when it should in fact fail. Is that the case? Also: why did you make the following change in =20 examples/cppunittest/TestAssertTest.cpp? What does the comment mean? - CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, =20 0.0, 1.0 ) ); + CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, =20 0.0, 1.0 ) ); // this one fails Quoting CppUnit development mailing list =20 <cpp...@li...>: > This seems to confirm that MSVC6 code generator is bug (does not respect > IEEE-754 standard in spite of what the doc claim). > > To work-around this, I added an explicit test for NaN value when testing > non-finite value for equalities. Here is the function: > // To work around this, a NaN is assumed to be detected if no strict > ordering is found. > inline bool floatingPointIsUnordered( double x ) > { > // x !=3D x will detect a NaN on conformant platform > // (2.0 < x && x < 1.0) will detect a NaN on non conformant platform: > // =3D> no ordering can be found for x. > return (x !=3D x) || (2.0 < x && x < 1.0); > } I don't understand why this works for you. According to the standard =20 (see e.g. page 8 of =20 http://www.cs.berkeley.edu/~wkahan/ieee754status/ieee754.ps) all =20 comparisons with NaN are false except "x !=3D x", which is true. You =20 state that MSVC6 gets "x !=3D x" wrong. Does it also get "x < y" wrong =20 and return true? > I'm not an expert on floating-point manipulation & NaN. Does any one see > anything wrong on the above implementation or the comments? The section of the paper referenced above also states that all =20 comparisons with NaN, except =3D=3D and !=3D, are *invalid* and thus signal.= =20 So the code you wrote is going to cause a problem if the FPU signals =20 are enabled. If we need this function, can we rename it floatingPointIsNan()? Then =20 I can create suitable automakery to use the standard isnan() on =20 systems that have it. On that note, does MSVC6 have something like =20 isnan(), maybe called _isnan()? http://msdn2.microsoft.com/en-us/library/tzthab44(VS.80).aspx Cheers, -Steve |
From: CppUnit d. m. l. <cpp...@li...> - 2007-02-25 08:52:42
|
CppUnit development mailing list wrote: > Hi Baptiste, > > I'm unclear on what problem you are solving here. My guess is that > > CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, nan, 1.0 ) > > was passing when it should in fact fail. Is that the case? Yes. I should have put this first. All the following unit tests were failing: CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, 0.0, 1.0 ) ); CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, nan, 1.0 ) ); CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, inf, 1.0 ) ); CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( inf, nan, 1.0 ) ); This was caused by the fact that equal = expected == actual; always evaluated to true whenever expected or actual was a NaN. > Also: why did you make the following change in > examples/cppunittest/TestAssertTest.cpp? What does the comment mean? > > - CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, > 0.0, 1.0 ) ); > + CPPUNIT_ASSERT_ASSERTION_FAIL( CPPUNIT_ASSERT_DOUBLES_EQUAL( nan, > 0.0, 1.0 ) ); // this one fails Ignore the comment, I forgot to remove it. It's done now. I hope it's clearer now. Baptiste. > Quoting CppUnit development mailing list > <cpp...@li...>: > >> This seems to confirm that MSVC6 code generator is bug (does not >> respect IEEE-754 standard in spite of what the doc claim). >> >> To work-around this, I added an explicit test for NaN value when >> testing non-finite value for equalities. Here is the function: >> // To work around this, a NaN is assumed to be detected if no strict >> ordering is found. >> inline bool floatingPointIsUnordered( double x ) >> { >> // x != x will detect a NaN on conformant platform >> // (2.0 < x && x < 1.0) will detect a NaN on non conformant >> platform: // => no ordering can be found for x. >> return (x != x) || (2.0 < x && x < 1.0); >> } > > I don't understand why this works for you. According to the standard > (see e.g. page 8 of > http://www.cs.berkeley.edu/~wkahan/ieee754status/ieee754.ps) all > comparisons with NaN are false except "x != x", which is true. You > state that MSVC6 gets "x != x" wrong. Does it also get "x < y" wrong > and return true? > > >> I'm not an expert on floating-point manipulation & NaN. Does any one >> see anything wrong on the above implementation or the comments? > > The section of the paper referenced above also states that all > comparisons with NaN, except == and !=, are *invalid* and thus signal. > So the code you wrote is going to cause a problem if the FPU signals > are enabled. > > > If we need this function, can we rename it floatingPointIsNan()? Then > I can create suitable automakery to use the standard isnan() on > systems that have it. On that note, does MSVC6 have something like > isnan(), maybe called _isnan()? > http://msdn2.microsoft.com/en-us/library/tzthab44(VS.80).aspx > > > Cheers, > -Steve > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to > share your opinions on IT & business topics through brief surveys-and > earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel |