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
|