【发布时间】:2015-05-17 23:05:00
【问题描述】:
我必须实现一个程序来计算 float 和 double 的机器 epsilon。
我写了这些函数:
int feps(){
//machine epsilon for float
float tmp=1;
int d=0;
while(1+(tmp=tmp/2)>1.0f)d++;
return d;
}
int deps(){
//machine epsilon for double
double tmp=1;
int d=0;
while(1+(tmp=tmp/2)>1.0)d++;
return d;
}
注意:
64 位机器编译器 gcc 4.9.1 目标:x86_64-linux-gnu
32 位机器编译器 gcc 4.8.2 目标:i686-linux-gnu
我在 64 位机上试了一下,结果是:
浮点数 23
双52
果然不出所料,然后我在32位的虚拟机上试了一下,结果很奇怪:
浮点数 63
双63
我还尝试使用 -mpc32、-mpc64 和 -mpc80 编译我的程序,结果如下:
- mpc32 浮点 23,双 23
-mpc64 浮点 52,双 52
-mpc80 浮点 63,双 63
我也在 64 位机器上尝试了这些编译选项,但结果总是 23 和 52。
我知道 float 是单精度,而 double 是双精度,但我的 32 位虚拟机的编译器可能对 float 和 double 都使用 binary80 格式?
我很确定我的代码是正确的,所以我认为问题与编译器有关或更微妙。
我花了一整天的时间搜索有关浮点的信息,并阅读了有关 MMX/SSE 指令的一些内容,但我不太了解,还有一些有关 x87 FPU 的内容可能会产生一些问题。
更新:
我要感谢所有帮助过我的人,我设法在 32 位虚拟机中获得了 float 和 double 的真实 epsilon 值,代码如下:
int feps(){
float tmp=1;
int d=0;
float tmp2=1;
do{
tmp2=1+(tmp=tmp/2);
d++;
}while(tmp2>1.0f);
return d-1;
}
int deps(){
double tmp=1;
int d=0;
double tmp2=1;
do{
tmp2=1+(tmp=tmp/2);
d++;
}while(tmp2>1.0);
return d-1;
}
如您所见,我们需要将中间结果放入变量中,这样我们可以防止 1+(tmp=tmp/2) 在循环中被评估为 long double测试。
【问题讨论】:
-
它是特定于编译器和实现的。阅读floating-point-gui.de
-
可能和你的虚拟机处理浮点指令有关
-
在您的 x86 机器上 FLT_EVAL_METHOD 为 2,但在 x86_64 上为 0。有关说明,请参见链接站点。
-
试试
printf("%zu\n",sizeof(float));。这不会告诉你什么是 epsilon,但会告诉你float在虚拟机上有多少字节。 -
您可能会被浮点寄存器中保存的值所欺骗。
标签: c floating-point double-precision