0

对不起我的英语不好。你能告诉我最小的 double 类型数,在它之后计算机认为 double 类型数等于零吗?

4

4 回答 4

4

实际零是零。结果可以以不同的方式变为零。双精度值范围为 +/-10^ +/-308(大约)。小于最小数字的数字将被视为零。使用#include <limits>,您可以得到numeric_limits<double>::denorm_min(),这是可以在 a 中表示的最小值double

但是您可以通过其他方式获得“零效应”。假设您有一个相当大的数字,1000 万,并且您添加(或减去 - 在本段的其余部分中将 add 读作加或减)一个非常小的数字,例如 1/10 百万,那么加法将无效,因为它在浮点数的尾数的实际值位之外——也就是53位的情况下double——那么效果会和加零一样。换句话说,即使你有一个不为零的数字,用它来添加另一个数字并不总是会改变另一个数字。

请参阅Wikipedia 上的 IEEE-754(确实存在其他浮点格式,但它们并不常见)。

于 2013-05-18T06:44:00.987 回答
2

你可以试试:

#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
于 2013-05-18T06:47:17.220 回答
0

单精度 32 位和双精度 64 位格式 IEEE 754

的最小正正常值double0x1.0p-1022 2.2250738585072014E-308

的最小正非正规值double0x0.0000000000001P-1022 4.9e-324

的最小正正常值float0x1.0p-126f 1.17549435E-38f

的最小正非正规值float0x0.000002P-126f 1.4e-45f

小于上述的正数可能会导致0,这取决于 Marc Glisse 评论的舍入模式。

于 2013-05-18T06:37:02.113 回答
-1

当您比较已计算的双精度值时,您永远不应该检查相等性。您应该检查是否在一个范围内。不这样做会导致你认为正确的事情很可能并非如此。

这可能是这个问题的重复。

于 2013-05-18T06:36:27.983 回答