Search code examples
c++gccvalgrind

Wrong result of std::fpclassify for long double using Valgrind


I bump into with strange behaviour. In this program I try check is floating point value equals to zero:

#include <cstdlib>
#include <cmath>
#include <iostream>

int main ()
{
    float       fa (0), fb (0);
    double      da (0), db (0);
    long double la (0), lb (0);

    cout << "Float:       " << (FP_ZERO == fpclassify (fa - fb) ) << endl;
    cout << "Double:      " << (FP_ZERO == fpclassify (da - db) ) << endl;
    cout << "Long double: " << (FP_ZERO == fpclassify (la - lb) ) << endl;
    cout << "Float:       " << (FP_ZERO == fpclassify (fa - 42) ) << endl;
    cout << "Double:      " << (FP_ZERO == fpclassify (da - 42) ) << endl;
    cout << "Long double: " << (FP_ZERO == fpclassify (la - 42) ) << endl;

    return EXIT_SUCCESS;
}

The result of the program is predictable:

$ ./llvlg 
Float:       1
Double:      1
Long double: 1
Float:       0
Double:      0
Long double: 0

But if I launch the program via Valgrind the result will be wrong for long double zero:

$ valgrind ./llvlg 
==7521== Memcheck, a memory error detector
==7521== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7521== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==7521== Command: ./llvlg
==7521== 
Float:       1
Double:      1
Long double: 0
Float:       0
Double:      0
Long double: 0
==7521== 
==7521== HEAP SUMMARY:
==7521==     in use at exit: 0 bytes in 0 blocks
==7521==   total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==7521== 
==7521== All heap blocks were freed -- no leaks are possible
==7521== 
==7521== For counts of detected and suppressed errors, rerun with: -v
==7521== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Is it a bug or expected behaviour?

UPD:
Source code of the program available here.
Build options: g++ main.cpp -O0 -o llvlg.
My environment:

  • $ uname -a Linux tiptop 4.8.0-53-generic #56-Ubuntu SMP Tue May 16 00:23:44 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

  • $ gcc --version gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005

  • $ valgrind --version valgrind-3.12.0.SVN

  • $ cat /proc/cpuinfo ... model name : Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz ...


Solution

  • This is the expected behaviour with Valgrind - a known limitation. Internally long double is only represented with 64bit (double) precision.

    See here.