Linux中的可执行文件是否会影响链接的dynamic库中的浮点精度?

在dynamic库中,我们遇到了浮点精度问题。

设置如下:

  • 我们有一个dynamic库,它在大量的浮点数上执行一个计算X. X由许多浮点操作组成。
  • 我们将这个dynamic库链接到两个可执行文件:A和B.
  • 在库中我们打印计算X的input。
  • 对于运行可执行文件A和B,报告完全相同的input(最多DBL_DIG小数)。
  • 然而,计算X的输出对于可执行文件A是不同于对于可执行文件B的。

这两个可执行文件和库都用C ++编写,并使用相同的GCC编译器版本在同一台机器上编译。 该库只用与可执行文件A相同的编译器设置编译一次,但可执行文件B的编译器设置可能不同。

由于使用了相同的库,所以在提供相同的input时,我们期望两个可执行文件具有相同的计算精度。 看起来像库的浮点精度受外部因素的影响,例如进程特定的configuration。

这是可能的,如果是这样,如何确保我们在两次运行(程序A和B)中获得相同的精度?

编辑1

我成功地创造了一个最小的例子来certificate不同之处。 如果我在库中使用下面的代码(比如计算X),结果对于两次运行(A和B)都是不同的:

float* value = new float; *value = 2857.0f; std::cout << std::setprecision(15) << std::log(*value) << std::endl; 

我也用二进制格式打印了浮点数,它们在最后一点显示出不同。

不幸的是,无法控制可执行文件A的整个构build链。实际上,A是一个dynamic库,它是从另一个可执行文件中使用的,我无法控制或不知道编译器选项。

我试着在可执行文件B上使用很多不同的优化编译器选项来查看是否可以得到与可执行文件A相同的结果,但是直到现在,这并没有解决问题。

编辑2

上面代码的汇编输出是:

 .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 

编辑3

正如在评论中所build议的,我在库中打印了浮点舍入模式和SSE状态信息。

对于两个运行(可执行文件A和B),我得到相同的值:

  • 舍入模式:895
  • 上证所状态:8114

你的问题的答案是: 是的,原则上一个进程可以改变你的代码在其中运行的浮点上下文


关于您的特定代码和值:

舍入模式(如Matteo建议) 可能会影响字符串格式,因为它会重复分10次 – 但我不能使用std::fesetround重现问题。

我也看不出它会如何影响你所说的不同的位模式。 汇编代码显示的文字是0x45329000 ,相当于2857.0,文字本身不能被浮点env所改变。