Jam*_*at7 8 c floating-point gcc compiler-errors
当运行如下所示的程序时,它会产生ok输出:
j= 0 9007199616606190.000000 = x
k= 0 9007199616606190.000000 = [x]
r= 31443101 0.000000 = m*(x-[x])
Run Code Online (Sandbox Code Playgroud)
但是当注释掉的行(即 //if (argc>1) r = atol(argv[1]);)被取消注释时,它会产生:
j= 20000 9007199616606190.000000 = x
k= 17285 9007199616606190.000000 = [x]
r= 31443101 0.000000 = m*(x-[x])
Run Code Online (Sandbox Code Playgroud)
即使该行应该没有效果,因为argc>1是假的.有没有人对这个问题有合理的解释?它是否可以在任何其他系统上重现?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
int j, k, m=10000;
double r=31443101, jroot=sqrt(83), x;
//if (argc>1) r = atol(argv[1]);
x = r * r * jroot;
j = m*(x-floor(x));
k = floor(m*(x-floor(x)));
printf ("j= %9d %24.6f = x\n", j, x);
printf ("k= %9d %24.6f = [x]\n", k, floor(x));
printf ("r= %9.0f %24.6f = m*(x-[x]) \n", r, m*(x-floor(x)));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意,测试系统=带有Linux 2.6.35.14-96.fc14.i686的AMD Athlon 64 5200+系统(即,在64位硬件上启动以运行32位操作系统)与gcc(GCC)4.5.1 20100924(红色帽子4.5.1-4)
更新 -几个小时前我发布了一条评论,即使用和不使用if语句生成的代码仅在堆栈偏移和一些跳过的代码中有所不同.我现在发现评论并不完全正确; 即对于非优化代码是正确的,但对于我执行的-O3代码则不然.
优化开关对问题的影响:
j=20000和k=17285j=20000(错误)和k=0(OK)无论如何,看看-O3 -S代码清单,这两种情况大多不同于跳过的if代码和堆栈偏移直到之前的行call floor,此时if-if代码fstpl比without-if代码多一个:
... ;; code without comment:
fmul %st, %st(1)
fxch %st(1)
fstpl (%esp)
fxch %st(1)
fstpl 48(%esp)
fstpl 32(%esp)
call floor
movl $.LC2, (%esp)
fnstcw 86(%esp)
movzwl 86(%esp), %eax
...
... ;; versus code with comment:
fmul %st, %st(1)
fxch %st(1)
fstpl (%esp)
fxch %st(1)
fstpl 48(%esp)
fstpl 32(%esp)
fstpl 64(%esp)
call floor
movl $.LC3, (%esp)
fnstcw 102(%esp)
movzwl 102(%esp), %eax
...
Run Code Online (Sandbox Code Playgroud)
我还没弄清楚差异的原因.
在我的系统上没有重复,Win7 运行带有 gcc 4.3.4 的 CygWin。无论有没有该if语句, 的值j都设置为零,而不是 20K。
我唯一的建议是使用它gcc -S来查看汇编器输出。这应该能告诉你出了什么问题。
具体来说,将汇编器输出生成到两个单独的文件,每个文件对应工作变体和非工作变体,然后 vgrep 它们(并排观察它们)以尝试确定差异。
顺便说一句,这在您的环境中是一个严重的失败。m10000 意味着必须等于x - floor(x)2。我一生都想不出任何实数会出现这种情况:-)