double 和 float 可能具有相同的精度?

Double and float may have the same precision?

我必须实现一个程序来计算 floatdouble.
的机器 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在循环测试中。

在 32 位平台上,ABI 约束使得使用历史浮点寄存器变得更简单;因此,编译器将 FLT_EVAL_METHOD 定义为 2。这就是您如何获得:

Float 63
Double 63

简而言之,当 FLT_EVAL_METHOD 被编译器定义为 2 时,就像在您的 32 位虚拟机上一样,浮点表达式和常量 are evaluated to 的精度 long double,不管它们的类型如何,只对左值赋值和显式强制转换从 long double 到实际浮点类型的计算值。在表达式 1+(tmp=tmp/2) 的顶层没有这样的构造,因此加法的计算精度为 long double.

这两个 post series 显示了一些示例,其中 FLT_EVAL_METHOD 除了您的示例之外还有所不同。根据 J.S.Myers 的解释,GCC 的行为是确定性的。 Clang 的行为是不确定的(过去和现在),开发人员对改进其编译器的这种模式没有兴趣。