我正在研究函数优化例程(Nelder-Mead算法的一种变体),它无法在非常特定的条件下收敛。
我已经确定float
变量(我们称之为a
)被分配了a
和另一个变量b
之间的平均值,它与之不同。只有一点。
更准确地说,每个变量的值如下:
float a = 25.9735966f; // 41CFC9ED
float b = 25.9735947f; // 41CFC9EC
现在我正在尝试将a
和a
之间的平均分配给b
:
a = 0.5 * (a+b);
当我在测试程序中编写此代码时,我得到了我想要的结果,即25.9735947
。但是在原始库代码的调试器中,我看到a的值仍为25.9735966
。我很确定我在两个程序上都有相同的编译器标志。 为什么这种单精度计算会产生不同的结果?
更新
正如@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)
澄清
我的代码是来自Numerical Recipes的Nelder-Mead代码的 ripoff 变体。违规行是这一行:
p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
在这一行中,p[i][j] == 25.9735966f
和p[ilo][j] == 25.9735947f
。 p[i][j]
中的结果值为25.9735966f
。
答案 0 :(得分:2)
我只是重新阅读IEEE 754-1985的相关部分,假设您的浮点实现符合该标准。我们唯一想到的是,在您的两个环境中有不同的舍入模式。这些是可能性:
25.9735947f
+INF
=> 25.9735966f
0
=> 25.9735947f
-INF
=> 25.9735947f
因此,唯一的可能性是您的调试环境具有朝向+ INF 的舍入模式。对我来说,没有其他合理的解释。