这种单精度操作的结果是如何舍入的?[或者为什么这个位1而不是0?]

lin*_*lof 5 c floating-point

我正在研究函数优化例程(Nelder-Mead算法的一种变体),它无法在非常特定的条件下收敛.

我已经确定了一个float变量,让我们称之为它a,被赋予平均值a和另一个b与之不同的变量.

更准确地说,每个变量的值如下:

float a = 25.9735966f; // 41CFC9ED
float b = 25.9735947f; // 41CFC9EC
Run Code Online (Sandbox Code Playgroud)

而现在我正试图分配和a之间的平均值:ab

a = 0.5 * (a+b);
Run Code Online (Sandbox Code Playgroud)

当我在测试程序中编写这段代码时,我得到了我想要的结果,即25.9735947.但是在原始库代码的调试器中,我看到a的值仍然存在25.9735966.我很确定我在两个程序上都有相同的编译器标志.有没有理由说这种单精度计算会产生不同的结果?

UPDATE

正如@PascalCuoq所要求的那样,我认为这就是所讨论的生产线的装配.这条线虽然做了一些其他事情,但我不确定乘法发生在哪里.

.loc 1 53 0 discriminator 2
movl    -60(%rbp), %eax
cltq
salq    $3, %rax
addq    -88(%rbp), %rax
movq    (%rax), %rax
movl    -44(%rbp), %edx
movslq  %edx, %rdx
salq    $2, %rdx
leaq    (%rax,%rdx), %rcx
movl    -44(%rbp), %eax
cltq
salq    $2, %rax
addq    -72(%rbp), %rax
movl    -60(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm1
movl    -52(%rbp), %edx
movslq  %edx, %rdx
salq    $3, %rdx
addq    -88(%rbp), %rdx
movq    (%rdx), %rdx
movl    -44(%rbp), %esi
movslq  %esi, %rsi
salq    $2, %rsi
addq    %rsi, %rdx
movss   (%rdx), %xmm0
addss   %xmm1, %xmm0
movss   .LC6(%rip), %xmm1
mulss   %xmm1, %xmm0
movss   %xmm0, (%rax)
movl    (%rax), %eax
movl    %eax, (%rcx)
Run Code Online (Sandbox Code Playgroud)

澄清

我的代码是Numerical Recipes的Nelder-Mead代码的ripoff变种.违规行是这一行:

p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
Run Code Online (Sandbox Code Playgroud)

在这一行,p[i][j] == 25.9735966fp[ilo][j] == 25.9735947f.得到的值p[i][j]25.9735966f.

Rol*_*lig 2

我刚刚重新阅读了 IEEE 754-1985 的相关部分,假设您的浮点实现符合该标准。唯一想到的是两个环境中有不同的舍入模式。这些是可能性:

  • 舍入到最接近的值,如果距离相等:将最低有效位设置为零 =>25.9735947f
  • +INF=>方向舍入25.9735966f
  • 0=>方向舍入25.9735947f
  • -INF=>方向舍入25.9735947f

因此,唯一的可能性是您的调试环境具有朝向 +INF 的舍入模式。对我来说,没有其他合理的解释。