我试图在一个循环中确定DBL_MIN(以测试另一个问题),我对输出感到惊讶:
double tmp(1.0);
double min(tmp);
while(tmp>0)
{
tmp/=2.0;
if(tmp>0) min=tmp;
else break;
}
cout<<scientific<<endl;
cout<<"Computed minimum: "<<min<<endl;
cout<<"Defined minimum: "<<DBL_MIN<<endl;
if(min>0 && min<DBL_MIN) cout<<"min is between 0 and DBL_MIN, HUH!"<<endl;
exit(1);
输出为:
Computed minimum: 4.940656e-324
Defined minimum: 2.225074e-308
min is between 0 and DBL_MIN, HUH!
当最小的正值为2.2e-308时,min如何保持值4.94e-324?据我了解,DBL_MIN以下的正值不应代表。在Linux下的Core i7上使用GCC 4.9.2进行了测试。
最佳答案
DBL_MIN
是最小归一化正值的两倍。这意味着这是其尾数不小于1.0
的最小值。如果选择较小的尾数,仍然可以使用较小的数字。
因此,您得到的是Denormal number。正如维基百科所说,
IEEE 754 standard控制double
(和其他浮点类型)的表示。该表示形式由指数e
和尾数m
(以及符号位,与该问题无关)组成。
对于指数e
不等于零的情况,对应的double
值为
(1 + m/2^52) * 2^(e-1023)
(
^
代表功率,52是m
中的位数,因此m/2^52
始终介于0到1(不包括0)之间。隐式(不包含在m
中)1
表示可以以这种方式存储的最小数字对应于m==0
和e==1
(请记住,此表示形式为e!=0
),其值为2^(-1022)
大约是
2.225074e-308
,即DBL_MIN
。但是,
e==0
以特殊方式处理。对于e==0
,将删除隐式1
,从而导致(m / 2^52) * 2^(-1022) // remember that e==0
这可以表示精确的零(使用
m==0
),也可以表示小的m
的次正态(或非正态)。最小的数字是m==1
,即2^(-1074)
或大约。 4.940656e-324
。