We ran into the problem of floating point precision in a dynamic library.
The configuration is as follows:
- We have a dynamic library that performs the calculation of X in a large array of floating point numbers. X consists of many floating point operations.
- We associate this dynamic library with two executable files: A and B.
- In the library, we print the input to calculate X.
- For both executable executables A and B, the exact input is reported (up to decimal digits DBL_DIG).
- The result of computing X, however, is different for executable A than for executable B.
Both executables and the library are written in C ++ and compiled on the same computer using the same version of the GCC compiler. The library only compiles once with the same compiler settings as executable A, but the compiler options for executable B can be different.
Since the same library is used, we expected the same calculation accuracy for both executable files while providing the same input. It seems that the accuracy of the floating point data depends on external factors, for example. process specific configurations.
Is this possible, and if so, how to make sure that we get the same accuracy in both runs (programs A and B)?
Change 1
I managed to create a minimal example demonstrating the differences. If I use the following code in the library (say, like computing X), the results will be different for both runs (A and B):
float* value = new float; *value = 2857.0f; std::cout << std::setprecision(15) << std::log(*value) << std::endl;
I also printed the floats in binary format and they show the difference in the last bit.
Unfortunately, it is not possible to control the entire assembly chain of the executable A. In fact, A is again a dynamic library that is used from another executable, for which I cannot control and do not know the compiler options.
I tried using many different optimization compiler options for executable B to find out if I can get the same results as executable A, but so far this has not solved the problem.
Edit 2
The assembler output of the above code:
.LFB1066: .cfi_startproc .cfi_personality 0x9b,DW.ref.__gxx_personality_v0 push rbp # .cfi_def_cfa_offset 16 .cfi_offset 6, -16 push rbx # .cfi_def_cfa_offset 24 .cfi_offset 3, -24 sub rsp, 8 #, .cfi_def_cfa_offset 32 mov edi, 4 #, call _Znwm@PLT # mov DWORD PTR [rax], 0x45329000 #* D.23338, mov rdi, QWORD PTR _ZSt4cout@GOTPCREL [rip] # tmp66, mov rax, QWORD PTR [rdi] # cout._vptr.basic_ostream, cout._vptr.basic_ostream mov rax, QWORD PTR -24[rax] # tmp68, mov QWORD PTR 8[rax+rdi], 15 # <variable>._M_precision, movsd xmm0, QWORD PTR .LC1[rip] #, call _ZNSo9_M_insertIdEERSoT_@PLT # mov rbx, rax # D.23465, mov rax, QWORD PTR [rax] # <variable>._vptr.basic_ostream, <variable>._vptr.basic_ostream mov rax, QWORD PTR -24[rax] # tmp73, mov rbp, QWORD PTR 240[rbx+rax] # D.23552, <variable>._M_ctype test rbp, rbp # D.23552 je .L9 #, cmp BYTE PTR 56[rbp], 0 # <variable>._M_widen_ok je .L5 #, movsx esi, BYTE PTR 67[rbp] # D.23550, <variable>._M_widen
Edit 3
As suggested in the comments, I printed both floating point rounding mode and SSE status information in the library.
For both runs (executable A and B) I get the same values:
- Rounding Mode: 895
- SSE Status: 8114