Bug 117742 - Wrong computations with long double on AMD64
Summary: Wrong computations with long double on AMD64
Status: RESOLVED DUPLICATE of bug 197915
Alias: None
Product: valgrind
Classification: Developer tools
Component: general (show other bugs)
Version: 3.1.0
Platform: Compiled Sources Linux
: NOR major
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-12-05 20:23 UTC by Wolfgang Bangerth
Modified: 2009-07-01 08:48 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
program that behaves differently under valgrind (383 bytes, text/plain)
2009-04-07 01:38 UTC, Bruno Haible
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Wolfgang Bangerth 2005-12-05 20:23:31 UTC
Valgrind and its associated tools do not treat long doubles any 
different than doubles. Take, for example, this little program: 
------------------- 
#include <iostream> 
 
int main () 
{ 
  long double x = 1.+1e-14; 
  for (unsigned int i=0; i<10; ++i) 
    { 
      x = static_cast<long double>(1.)+(x-1)/2; 
      std::cout << x-1 << std::endl; 
    } 
} 
------------------ 
When compiled and run on an opteron box with gcc 3.3.5, I get this: 
 
spec/src> c++ y.cc 
spec/src> ./a.out  
4.996e-15 
2.498e-15 
1.249e-15 
6.245e-16 
3.1225e-16 
1.56125e-16 
7.80626e-17 
3.90313e-17 
1.95156e-17 
9.75782e-18 
spec/src> valgrind ./a.out  
==7430== Memcheck, a memory error detector. 
==7430== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al. 
==7430== Using LibVEX rev 1471, a library for dynamic binary translation. 
==7430== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP. 
==7430== Using valgrind-3.1.0, a dynamic binary instrumentation framework. 
==7430== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al. 
==7430== For more details, rerun with: -v 
==7430==  
4.88498e-15 
2.44249e-15 
1.33227e-15 
6.66134e-16 
4.44089e-16 
2.22045e-16 
0 
0 
0 
0 
==7430==  
==7430== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 8 from 5) 
==7430== malloc/free: in use at exit: 0 bytes in 0 blocks. 
==7430== malloc/free: 0 allocs, 0 frees, 0 bytes allocated. 
==7430== For counts of detected errors, rerun with: -v 
==7430== No malloc'd blocks -- no leaks are possible. 
 
Note the difference in output! 
 
The problem with this is, of course, that it leads to algorithms that 
converge when run on the command line, but loop forever when run under 
valgrind. 
 
Best 
  Wolfgang
Comment 1 Julian Seward 2005-12-05 20:36:55 UTC
> Valgrind and its associated tools do not treat long doubles any
> different than doubles.


That's true.  It's a documentated limitation:
http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits

> The problem with this is, of course, that it leads to algorithms that
> converge when run on the command line, but loop forever when run under
> valgrind.


It also means your program is inherently unportable - you have no chance
of it working on ppc, nor if you compile it to use SSE on x86/amd64
for example if it was vectorised.
Comment 2 M Welinder 2008-06-25 21:17:45 UTC
> It also means your program is inherently unportable

Not really.  What it means is that gcc+valgrind does not implement C99.
Take this program, for example:

#include <stdio.h>
#include <float.h>
#include <assert.h>
int
main (int argc, char **argv)
{
  long double ld = argc * LDBL_MIN;
  printf ("%Lg\n", ld);
  assert (ld > 0);
  return 0;
}

When you run that with no arguments, argc==1, then C99 guarantees that
the program will print a positive number and exit cleanly.  Under
valgrind, it instead prints zero and aborts.  (I don't have the c++
standard handy, but I'm sure it says something of the same nature.)

That Valgrind does not handly this is all clearly documented, but please
don't blame it on the subject program.
Comment 3 Wolfgang Bangerth 2008-06-29 01:01:54 UTC
> It also means your program is inherently unportable - you have no chance 
> of it working on ppc

I think this is an unfair characterization. It may be true that one shouldn't
be using things like
  long double eps = 1e-19;
and test for that as a convergence criterion. But what people do in their
codes is stuff like
  long double eps = std::numeric_limits<long double>::eps();
This *is* portable, but leads to different behavior in algorithms when run
freestanding and under valgrind on x86.


> nor if you compile it to use SSE on x86/amd64 
> for example if it was vectorised.

That's also not quite correct since long double variables can't be vectorized
anyway.


Either way, the point I wanted to make is not so much whether the example
program I showed is good or bad style (it's a reduced testcase, not part
of a portable program) but that with this program we get different behavior
for a program depending on whether it is run under valgrind or not. That's
certainly an undesirable feature.

Thanks
 Wolfgang
Comment 4 Bruno Haible 2009-04-07 01:38:46 UTC
Created attachment 32672 [details]
program that behaves differently under valgrind

Here is another program that behaves differently under valgrind than
natively.

Natively:

1020 5.61779e+306 1020 0.5
1021 1.12356e+307 1021 0.5
1022 2.24712e+307 1022 0.5
1023 4.49423e+307 1023 0.5
1024 8.98847e+307 1024 0.5
1025 1.79769e+308 1025 0.5
1026 3.59539e+308 1026 0.5
1027 7.19077e+308 1027 0.5
1028 1.43815e+309 1028 0.5

Under "valgrind --tool=memcheck" (on AMD64):

1020 5.61779e+306 1020 0.5
1021 1.12356e+307 1021 0.5
1022 2.24712e+307 1022 0.5
1023 4.49423e+307 1023 0.5
1024 8.98847e+307 1024 0.5
1025 inf 0 inf

This program is not unportable; it is part of the gnulib testsuite and known
to succeed on all platforms.

The problem is that valgrind appears to assume a different format for
'long double', which does not match the constants in <float.h>.
Comment 5 Julian Seward 2009-04-07 09:35:21 UTC
> This program is not unportable; it is part of the gnulib testsuite and known
> to succeed on all platforms.

What does "succeed" mean in this context?  "Produces identical results
on all platforms?"  FWIW, here's the output on openSUSE 10.3 on ppc32
(running natively):

1020 5.61779e+306 1020 0.5
1021 1.12356e+307 1021 0.5
1022 2.24712e+307 1022 0.5
1023 4.49423e+307 1023 0.5
1024 8.98847e+307 1024 0.5
Comment 6 Nicholas Nethercote 2009-07-01 08:47:18 UTC

*** This bug has been marked as a duplicate of bug 179915 ***
Comment 7 Nicholas Nethercote 2009-07-01 08:48:25 UTC

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