对不起我的英语不好。你能告诉我最小的 double 类型数,在它之后计算机认为 double 类型数等于零吗?
4 回答
实际零是零。结果可以以不同的方式变为零。双精度值范围为 +/-10^ +/-308(大约)。小于最小数字的数字将被视为零。使用#include <limits>
,您可以得到numeric_limits<double>::denorm_min()
,这是可以在 a 中表示的最小值double
。
但是您可以通过其他方式获得“零效应”。假设您有一个相当大的数字,1000 万,并且您添加(或减去 - 在本段的其余部分中将 add 读作加或减)一个非常小的数字,例如 1/10 百万,那么加法将无效,因为它在浮点数的尾数的实际值位之外——也就是53位的情况下double
——那么效果会和加零一样。换句话说,即使你有一个不为零的数字,用它来添加另一个数字并不总是会改变另一个数字。
请参阅Wikipedia 上的 IEEE-754(确实存在其他浮点格式,但它们并不常见)。
你可以试试:
#include <limits>
std::numeric_limits<double>::denorm_min();
非正规(又名次正规)数字的文档(此处)。
如果此数字除以例如 2,则结果为 0。
要在特定平台上检查此值,可以使用以下代码:
#include <iostream>
#include <limits>
using std::cout;
using std::endl;
int main() {
typedef double real;
union dbl {
real d;
unsigned char c[sizeof(d)];
dbl(const dbl &n = 0.0) : d(n.d) {}
dbl(double n) : d(n) {}
void pr(const char *txt = 0) const {
if (txt) cout << txt << ": ";
cout << d << ":";
for (int i = sizeof(d) -1; i >= 0; --i)
cout << std::hex << " " << (int)c[i];
cout << endl;
}
};
dbl n = 1.0;
for (; n.d > 0.0; n.d /= 2.0)
n.pr();
n.pr("zero");
n.d = std::numeric_limits<real>::min();
n.pr("min");
n.d = std::numeric_limits<real>::denorm_min();
n.pr("denorm_min");
}
在 32 位 linux (intel cpu) 上输出(关于双格式的文档):
1: 3f f0 0 0 0 0 0 0
0.5: 3f e0 0 0 0 0 0 0
0.25: 3f d0 0 0 0 0 0 0
0.125: 3f c0 0 0 0 0 0 0
0.0625: 3f b0 0 0 0 0 0 0
...
8.9003e-308: 0 30 0 0 0 0 0 0
4.45015e-308: 0 20 0 0 0 0 0 0
2.22507e-308: 0 10 0 0 0 0 0 0
1.11254e-308: 0 8 0 0 0 0 0 0
5.56268e-309: 0 4 0 0 0 0 0 0
...
7.90505e-323: 0 0 0 0 0 0 0 10
3.95253e-323: 0 0 0 0 0 0 0 8
1.97626e-323: 0 0 0 0 0 0 0 4
9.88131e-324: 0 0 0 0 0 0 0 2
4.94066e-324: 0 0 0 0 0 0 0 1
zero: 0: 0 0 0 0 0 0 0 0
min: 2.22507e-308: 0 10 0 0 0 0 0 0
denorm_min: 4.94066e-324: 0 0 0 0 0 0 0 1
如果real
定义为long double
输出为:
1: 0 0 3f ff 80 0 0 0 0 0 0 0
0.5: 0 0 3f fe 80 0 0 0 0 0 0 0
0.25: 0 0 3f fd 80 0 0 0 0 0 0 0
0.125: 0 0 3f fc 80 0 0 0 0 0 0 0
0.0625: 0 0 3f fb 80 0 0 0 0 0 0 0
...
5.83232e-4950: 0 0 0 0 0 0 0 0 0 0 0 10
2.91616e-4950: 0 0 0 0 0 0 0 0 0 0 0 8
1.45808e-4950: 0 0 0 0 0 0 0 0 0 0 0 4
7.2904e-4951: 0 0 0 0 0 0 0 0 0 0 0 2
3.6452e-4951: 0 0 0 0 0 0 0 0 0 0 0 1
zero: 0: 0 0 0 0 0 0 0 0 0 0 0 0
min: 3.3621e-4932: 0 0 0 1 80 0 0 0 0 0 0 0
denorm_min: 3.6452e-4951: 0 0 0 0 0 0 0 0 0 0 0 1
或为float
:
1: 3f 80 0 0
0.5: 3f 0 0 0
0.25: 3e 80 0 0
0.125: 3e 0 0 0
0.0625: 3d 80 0 0
...
2.24208e-44: 0 0 0 10
1.12104e-44: 0 0 0 8
5.60519e-45: 0 0 0 4
2.8026e-45: 0 0 0 2
1.4013e-45: 0 0 0 1
zero: 0: 0 0 0 0
min: 1.17549e-38: 0 80 0 0
denorm_min: 1.4013e-45: 0 0 0 1
在单精度 32 位和双精度 64 位格式 IEEE 754
的最小正正常值double
是0x1.0p-1022
2.2250738585072014E-308
。
的最小正非正规值double
是0x0.0000000000001P-1022
4.9e-324
。
的最小正正常值float
是0x1.0p-126f
1.17549435E-38f
。
的最小正非正规值float
是0x0.000002P-126f
1.4e-45f
。
小于上述的正数可能会导致0
,这取决于 Marc Glisse 评论的舍入模式。
当您比较已计算的双精度值时,您永远不应该检查相等性。您应该检查是否在一个范围内。不这样做会导致你认为正确的事情很可能并非如此。
这可能是这个问题的重复。