Bug 121029 - std::pow returns different float values than without valgrind
Summary: std::pow returns different float values than without valgrind
Status: RESOLVED DUPLICATE of bug 197915
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: 3.0.0
Platform: Compiled Sources Linux
: NOR normal
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-01-30 13:02 UTC by Michael Doppler
Modified: 2009-06-26 02:38 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Doppler 2006-01-30 13:02:02 UTC
Version:           3.0.0 (using KDE Devel)
Installed from:    Compiled sources
Compiler:          g++ 3.2.3 
OS:                Linux

The comparisions in the following testprogram all result in true when invoked directly. When run using valgrind, the comparisons with the result of std::pow with 5.0, 9.0 and 10.0 result in false.

The test was compiled with gcc 3.2.3 under i386 and with gcc 4.0 under ppc and returned the same result without valgrind.

This is probably related to the 3.0.0 changes in its IEEE754 floating point implementation mentioned in http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits. 

Valgrind versions 2.4.1 and lower seem to be unaffected by this problem.


Testprogram:

#include <iostream>

int main( void )
{
   std::cout << "std::pow( 1.0, 0.5 ) == 1.0 " << ( std::pow( 1.0, 0.5 ) == 1.0 ) << std::endl;
   std::cout << "std::pow( 4.0, 0.5 ) == 2.0 " << ( std::pow( 4.0, 0.5 ) == 2.0 ) << std::endl;
   std::cout << "std::pow( 9.0, 0.5 ) == 3.0 " << ( std::pow( 9.0, 0.5 ) == 3.0 ) << std::endl;
   std::cout << "std::pow( 16.0, 0.5 ) == 4.0 " << ( std::pow( 16.0, 0.5 ) == 4.0 ) << std::endl;
   std::cout << "std::pow( 25.0, 0.5 ) == 5.0 " << ( std::pow( 25.0, 0.5 ) == 5.0 ) << std::endl;
   std::cout << "std::pow( 36.0, 0.5 ) == 6.0 " << ( std::pow( 36.0, 0.5 ) == 6.0 ) << std::endl;
   std::cout << "std::pow( 49.0, 0.5 ) == 7.0 " << ( std::pow( 49.0, 0.5 ) == 7.0 ) << std::endl;
   std::cout << "std::pow( 64.0, 0.5 ) == 8.0 " << ( std::pow( 64.0, 0.5 ) == 8.0 ) << std::endl;
   std::cout << "std::pow( 81.0, 0.5 ) == 9.0 " << ( std::pow( 81.0, 0.5 ) == 9.0 ) << std::endl;
   std::cout << "std::pow( 100.0, 0.5 ) == 10.0 " << ( std::pow( 100.0, 0.5 ) == 10.0 ) << std::endl;
   std::cout << "std::pow( 121.0, 0.5 ) == 11.0 " << ( std::pow( 121.0, 0.5 ) == 11.0 ) << std::endl;
   std::cout << "std::pow( 144.0, 0.5 ) == 12.0 " << ( std::pow( 144.0, 0.5 ) == 12.0 ) << std::endl;
   return 0;
}
Comment 1 Michael Doppler 2006-01-30 13:46:58 UTC
This problem also affects version 3.1.0 of valgrind.
Comment 2 Tom Hughes 2006-01-30 13:52:32 UTC
As you say, this is almost certainly the issue described in the documentation. Julian will know more than me on this but I don't believe there are any current plans to support 80 bit x87 precision.

One thing I'm a bit confused about is that you mention PPC in the description - do you mean that this is also failing in the same way on a PPC system? If so then it would rule out the 80 bit issue as that is x87 specific. Compiling -mfpmath=sse on an x86 box would also rule that out.

Another possibility would be a rounding mode issue I guess - does --show-emwarns=yes report any warnings about rounding modes?

You shouldn't really be doing equality tests like that on floating point values though - it isn't a reliable means of comparing a floating point result.
Comment 3 Michael Doppler 2006-01-30 14:10:35 UTC
Yes on ppc the testprogram produces the same result as on x86 without valgrind: all comparisons succeed. 

I just tested with -mfpmath=sse under Linux/gcc 3.2.3: all comparisons succeed when invoked directly and fail when run using valgrind 3.1.0. 

So I guess the bit precision can be ruled out for this problem.

The --show-emwarns=yes switch does not result in any warnings.

>You shouldn't really be doing equality tests like that on floating point values >though - it isn't a reliable means of comparing a floating point result. 

I know, this comparisons just exist in one of my regression tests, elsewhere they are done with a certain tolerance. But it would still be nice if valgrind produced the same result as the native run of the program.
Comment 4 Michael Doppler 2006-01-30 14:15:29 UTC
>I just tested with -mfpmath=sse under Linux/gcc 3.2.3: all comparisons succeed >when invoked directly and fail when run using valgrind 3.1.0.

Sorry, it seems that I have missed a warning while compiling with -mfpmath=sse:

cc1plus: warning: SSE instruction set disabled, using 387 arithmetics

So maybe the precision theory can not be completely ruled out yet. That it works the same way on PPC as on x86 is still strange though.
Comment 5 Michael Doppler 2006-01-30 14:36:07 UTC
OK, now I tested on Linux x86_64 (aka amd64) using gcc 3.4.4 and valgrind 3.1.0 compiled for x86_64:

The valgrind run is now identical to the native run, with or without -mfpmath=sse set. All equality comparisons succeed.
Comment 6 Tom Hughes 2006-01-30 15:03:45 UTC
Interesting - x86_64 will default to SSE maths.

Add -msse2 to get SSE support on x86 - so "-fpmath=sse -msse2" should get it to use SSE for the FP code. That might not help if the problem is in libstdc++ of course, unless that was recompiled the same way.

It sounds like there might be two issues - the 80 bit precision issue on x86 (not present when using SSE math which is 64 bit) and some sort of PPC issue.
Comment 7 Michael Doppler 2006-01-30 15:31:14 UTC
Results with SSE on x86 ("-mfpmath=sse -msse2"): 
All equality tests succeed when run natively and the tests for 5.0, 9.0 and 10.0 fail when run under valgrind, so the behavior is equivalent to the non SSE tests on the same platform.

Note that on PPC/OS X I just ran the test natively, because I have no valgrind on that platform.
Comment 8 Tom Hughes 2006-01-30 15:35:18 UTC
So you haven't actually run under valgrind on PPC then? Sorry I think I misunderstood what you were saying about that.

By the sounds of it this is the 80 bit x87 issue document in the manual then.
Comment 9 Michael Doppler 2006-01-30 15:57:20 UTC
What puzzles me a bit is that natively the test program produces the same results on all platform/compiler combinations using 64bit (SSE/PPC) and 80bit (x86 non SSE) arithmetic, but only the amd64 valgrind produces the same result as the native run. 
Comment 10 Julian Seward 2006-01-30 19:40:14 UTC
I'll look into it this week, since I'm looking at FP accuracy issues
anyway this week.
Comment 11 Tobias Polzin 2006-04-08 01:42:04 UTC
I traced a valgrind problem I had to a simpler example. I conjecture that it´s not too much of interest for you. But I want to report it, as it took me a while to understand that although all floats are 64 bit doubles, the intermediate 100100/a is probably 80bit and causes the problem.
-----------------------------------
#include <iostream>
int main()
{
  double b = 3.6;
  double a = 60/b;
  double c = 100100/a;
  std::cout << c << " " << int( c ) << " " << int(100100/a ) << "\n";
}
-----------------------------------
The program gives "6006 6006 6005" with gcc-3.4.2, gcc-4.0.1, gcc-4.1.0 on a 
  Linux simusrv6 2.6.11-gentoo-r9 #2 SMP Fri May 27 11:53:26 CEST 2005 i686 
  Intel(R) Pentium(R) 4 CPU 3.00GHz GenuineIntel GNU/Linux
and 
  Linux gentoo29 2.6.10-co-0.6.2 #5 Sat Feb 5 10:19:16 IST 2005 
  i686 Intel(R) Pentium(R) 4 CPU 3.00GHz GenuineIntel GNU/Linux

But with valgrind and without valgrind but with "-mfpmath=sse -msse2" it produces "6006 6006 6006".
Comment 12 Nicholas Nethercote 2009-06-26 02:38:04 UTC

*** This bug has been marked as a duplicate of bug 197915 ***