Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::cos gives different result when run with valgrind

I've discovered an issue impacting several unit tests at my work, which only happens when the unit tests are run with valgrind, in that the value returned from std::cos and std::sin are different for identical inputs depending on if the unit test is run in isolation versus run under valgrind.

This issue only seems to happen for some specific inputs, because many unit tests pass which run through the same code.

Here's a minimally reproducible example (slightly worsened so that my compiler wouldn't optimize away any of the logic):

#include <complex>
#include <iomanip>
#include <iostream>

int main()
{
    std::complex<long double> input(0,0), output(0,0);

    input = std::complex<long double>(39.21460183660255L, -40);
    std::cout << "input: " << std::setprecision(20) << input << std::endl;

    output = std::cos(input);
    std::cout << "output: " << std::setprecision(20) << output << std::endl;

    if (std::abs(output) < 5.0)
    {
        std::cout << "TEST FAIL" << std::endl;
        return 1;
    }

    std::cout << "TEST PASS" << std::endl;
    return 0;
}

Output when run normally:

input: (39.21460183660254728,-40)
output: (6505830161375283.1118,117512680740825220.91)
TEST PASS

Output when run under valgrind:

input: (39.21460183660254728,-40)
output: (0.18053126362312540976,3.2608771240037195405)
TEST FAIL

Notes:

  • OS: Red Hat Enterprise Linux 7
  • Compiler: Intel OneAPI 2022 Next generation DPP/C++ Compiler
  • Valgrind: 3.20 (built with same compiler), also occurred on official distribution of 3.17
  • Issue did not manifest when unit tests were built with GCC-7 (cannot go back to that compiler) or GCC-11 (another larger bug with boost prevents us from using this with valgrind)
  • -O0/1/2/3 make no difference on this issue
  • only compiler flag I have set is "-fp-speculation=safe", which otherwise if unset causes numerical precision issues in other unit tests

Is there any better ways I can figure out what's going on to resolve this situation, or should I submit a bug report to valgrind? I hope this issue is benign but I want to be able to trust my valgrind output.

like image 349
Yattabyte Avatar asked Sep 10 '25 23:09

Yattabyte


1 Answers

you are probably hitting a valgrind limitation.

from https://valgrind.org/docs/manual/manual-core.html:

Valgrind has the following limitations in its implementation of x86/AMD64 floating point relative to IEEE754.

Precision: There is no support for 80 bit arithmetic. Internally, Valgrind represents all such "long double" numbers in 64 bits, and so there may be some differences in results. Whether or not this is critical remains to be seen. Note, the x86/amd64 fldt/fstpt instructions (read/write 80-bit numbers) are correctly simulated, using conversions to/from 64 bits, so that in-memory images of 80-bit numbers look correct if anyone wants to see.

The impression observed from many FP regression tests is that the accuracy differences aren't significant. Generally speaking, if a program relies on 80-bit precision, there may be difficulties porting it to non x86/amd64 platforms which only support 64-bit FP precision. Even on x86/amd64, the program may get different results depending on whether it is compiled to use SSE2 instructions (64-bits only), or x87 instructions (80-bit). The net effect is to make FP programs behave as if they had been run on a machine with 64-bit IEEE floats, for example PowerPC. On amd64 FP arithmetic is done by default on SSE2, so amd64 looks more like PowerPC than x86 from an FP perspective, and there are far fewer noticeable accuracy differences than with x86.

Rounding: Valgrind does observe the 4 IEEE-mandated rounding modes (to nearest, to +infinity, to -infinity, to zero) for the following conversions: float to integer, integer to float where there is a possibility of loss of precision, and float-to-float rounding. For all other FP operations, only the IEEE default mode (round to nearest) is supported.

Numeric exceptions in FP code: IEEE754 defines five types of numeric exception that can happen: invalid operation (sqrt of negative number, etc), division by zero, overflow, underflow, inexact (loss of precision).

like image 153
OznOg Avatar answered Sep 12 '25 13:09

OznOg