计算双

时间:2017-08-22 17:00:13

标签: c floating-point

作为C编程语言练习的一部分"我试图找到一种方法来计算我的计算机上可能的最大浮动和最大可能的双倍。下面显示的技术适用于float s(计算最大浮点数)但不适用于double

// max float:
float f = 1.0;
float last_f;
float step = 9.0;
while(1) {
    last_f = f;
    f *= (1.0 + step);
    while (f == INFINITY) {
        step /= 2.0;
        f  = last_f * (1.0 + step);
    }
    if (! (f > last_f) )
        break;
}
printf("calculated float max : %e\n", last_f);
printf("limits.h float max   : %e\n", FLT_MAX);
printf("diff                 : %e\n", FLT_MAX - last_f);
printf("The expected value?  : %s\n\n", (FLT_MAX == last_f)? "yes":"no");

// max double:
double d = 1.0;
double last_d;
double step_d = 9.0;
while(1) {
    last_d = d;
    d *= (1.0 + step_d);
    while (d == INFINITY) {
        step_d /= 2.0;
        d  = last_d * (1.0 + step_d);
    }
    if (! (d > last_d) )
        break;
}
printf("calculated double max: %e\n", last_d);
printf("limits.h double max  : %e\n", DBL_MAX);
printf("diff                 : %e\n", DBL_MAX - last_d);
printf("The expected value?  : %s\n\n", (DBL_MAX == last_d)? "yes":"no");

,结果是:

calculated float max : 3.402823e+38
limits.h float max   : 3.402823e+38
diff                 : 0.000000e+00
The expected value?  : yes

calculated double max: 1.797693e+308
limits.h double max  : 1.797693e+308
diff                 : 1.995840e+292
The expected value?  : no

在我看来它仍然在第二种情况下使用单精度计算。

我缺少什么?

2 个答案:

答案 0 :(得分:5)

当第一种情况下的计算精度高于float且第二种情况下的double更宽时,OP的方法有效。

在第一种情况下,OP报告FLT_EVAL_METHOD == 0,因此float计算完成floatdouble完成double。请注意,float step ... 1.0 + stepdouble计算。

以下代码强制计算到 double ,因此即使使用FLT_EVEL_METHOD==2我也可以复制OP的问题(使用long double进行内部计算。)

  volatile double d = 1.0;
  volatile double last_d;
  volatile double step_d = 9.0;
  while(1) {
      last_d = d;
      d *= (1.0 + step_d);
      while (d == INFINITY) {
          step_d /= 2.0;
          volatile double sum = 1.0 + step_d;
          d  = last_d * sum;
          //d  = last_d  + step_d*last_d;
      }
      if (! (d > last_d) ) {
        break;
      }
  }

diff                 : 1.995840e+292
The expected value?  : no

相反,OP应该使用以下内容,当1.0 + step_d较小时,不会形成step_d不精确总和,而是形成完全 step_d*last_d的产品。通过在d中提供额外的计算精度,第二种形式可以更准确地计算新d。采用OP的方法不需要更高精度的FP。

          d  = last_d  + step_d*last_d;

diff                 : 0x0p+0 0.000000e+00
The expected value?  : yes

答案 1 :(得分:1)

文字n.0的表达式都是双精度浮点类型。这允许使用更高精度的中间值来计算f的赋值。

这种效果允许算法在浮动情况下收敛。

使用严格的双精度浮点,这种收敛是不可能的。

如果你在浮点数的文字中使用了f后缀,那么也不会出现收敛。

如果您的平台具有更宽的long double类型,则修复将在文字上使用长双后缀。