C 计算双精度的范围

C 计算双精度的范围,c,floating-point,C,Floating Point,作为“C编程语言”练习的一部分,我试图找到一种方法来计算计算机上的最大可能浮点和最大可能双精度。下面显示的技术适用于floats(计算最大浮动),但不适用于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;

作为“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
在我看来,在第二种情况下,它仍然使用单一精度进行计算


我缺少什么?

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

正是这种效应使得算法能够在浮点情况下收敛

对于严格的双精度浮点,这种收敛是不可能的

如果在float情况下对文本使用了f后缀,那么也不会发生收敛


如果您的平台具有更宽的long double类型,修复方法是在文本上使用long double后缀。

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

正是这种效应使得算法能够在浮点情况下收敛

对于严格的双精度浮点,这种收敛是不可能的

如果在float情况下对文本使用了f后缀,那么也不会发生收敛


如果您的平台具有较宽的long double类型,修复方法是在文本上使用long double后缀。

OP的方法在第一种情况下以比
float
更宽的精度进行计算,在第二种情况下以比
double
更宽的精度进行计算时有效

在第一种情况下,OP报告
FLT\u EVAL\u METHOD==0
因此
float
计算按
float
进行,
double
计算按
double
进行。请注意,
float步骤。。。1.0+步骤
是一个
双重
计算


下面的代码强制计算加倍,因此即使使用
FLT\u EVEL\u METHOD==2,我也可以复制OP的问题(内部计算使用
long double

相反,当
步骤d
很小时,OP应该使用以下方法,而不是形成
步骤d*最后一个步骤d
不精确的
1.0+步骤d
,而是形成
步骤d*最后一个步骤d
精确的乘积。第二种形式通过在
d
中提供额外的计算精度位,使新
d
的计算更加精确。采用OP方法不需要更高精度的FP

          d  = last_d  + step_d*last_d;

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

在第一种情况下,OP的方法适用于精度大于
float
的计算,在第二种情况下适用于精度大于
double
的计算

在第一种情况下,OP报告
FLT\u EVAL\u METHOD==0
因此
float
计算按
float
进行,
double
计算按
double
进行。请注意,
float步骤。。。1.0+步骤
是一个
双重
计算


下面的代码强制计算加倍,因此即使使用
FLT\u EVEL\u METHOD==2,我也可以复制OP的问题(内部计算使用
long double

相反,当
步骤d
很小时,OP应该使用以下方法,而不是形成
步骤d*最后一个步骤d
不精确的
1.0+步骤d
,而是形成
步骤d*最后一个步骤d
精确的乘积。第二种形式通过在
d
中提供额外的计算精度位,使新
d
的计算更加精确。采用OP方法不需要更高精度的FP

          d  = last_d  + step_d*last_d;

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

我认为它适用于float,因为有些比较是以双精度进行的。提示:使用
%a“
查看
last\u d/DBL\u MAX
@Bathsheba的所有详细信息-是的,我想也是这样,只是现在还不知道如何解决这个问题:)我打赌我的工作就是解决这个问题-回答如下。我看到的问题是
d=last\u d*(1.0+step\d)vs.可能
d=last\u d+step\u d*last\u d
作为第一个可以使
加倍
中间和
1.0+步骤d
,即
1.0
,即使没有
步骤d!=0
而第二种形式可以使用更宽一点的FP数学。您是否使用
d=last\u d+step\u d*last\u d?我认为它适用于float,因为有些比较是以双精度进行的。提示:使用
%a“
查看
last\u d/DBL\u MAX
@Bathsheba的所有详细信息-是的,我想也是这样,只是现在还不知道如何解决这个问题:)我打赌我的工作就是解决这个问题-回答如下。我看到的问题是
d=last\u d*(1.0+step\d)vs.可能
d=last\u d+step\u d*last\u d
作为第一个可以使
加倍
中间和
1.0+步骤d
,即
1.0
,即使没有
步骤d!=0
而第二种形式可以使用更宽一点的FP数学。您是否使用
d=last\u d+step\u d*last\u d?为什么局部变量被标记为易变的
?这就是迫使计算使用双精度的原因吗?@Groo是的,部分。如果我的
double
变量不是
volatile
,那么使用
FLT\u EVEL\u METHOD==2
,可能会出现各种FP数学,精度更高。因此,尝试强制计算只在
double
处进行,并将
last_f*(1.0+步)
分为两步,确保
1.0+步
总和不会以更高的精度在内部保留。然后使用
d=last\ud+步骤d*last\ud重新形成代码(甚至
v