Double和float可以具有相同的精度?

时间:2015-03-15 21:47:57

标签: c floating-point double-precision

我必须实现一个程序来计算 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 Float 23,Double 23
-mpc64 Float 52,Double 52
-mpc80 Float 63,Double 63
我也在64位机器上尝试了这些编译选项,但结果总是23和52 我知道float是单精度而double是双精度但我的32位虚拟机的编译器可能使用binary80格式用于float和double吗?

我非常确定我的代码是正确的,所以我认为这个问题与编译器或更微妙的东西有关。 我花了一整天时间搜索有关浮点数的信息,并且我已经阅读了有关MMX / SSE指令的内容,但我对此并不了解,而且x87 FPU可能会产生一些问题。< / p>

<小时/> 的更新
我要感谢所有帮助过我的人,我设法在32位虚拟机中获得浮动和双倍的真实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 测试。

1 个答案:

答案 0 :(得分:3)

在32位平台上,ABI约束使得使用历史浮点寄存器变得更加简单;因此,编译器将FLT_EVAL_METHOD定义为2.这就是你得到的结果:

Float 63
Double 63

简而言之,当编译器将FLT_EVAL_METHOD定义为2时,就像32位虚拟机上的情况一样,浮点表达式和常量are evaluated to的精度为long double无论它们的类型如何,只有lvalues和显式转换的赋值将计算值从long double四舍五入到实际的浮点类型。表达式1+(tmp=tmp/2)的顶层没有这样的结构,因此添加的计算精度为long double

此两个帖子series显示了一些示例,其中FLT_EVAL_METHOD除了您之外还有所不同。 GCC的行为是确定性的,并且根据J.S.Myers的解释。 Clang的行为是不确定的(当时和现在),开发人员对改进他们的编译器模式没什么兴趣。