有人可以向我解释为什么浮动x = 0.1 * 7不会导致x == 0.7为真?

时间:2013-04-28 21:25:34

标签: c++ floating-point

编辑:这里有很多不满的成员,因为这个问题在网站上有重复。在我的辩护中,我尝试首先搜索答案,也许我使用的搜索关键字很差,但我找不到这个特定代码示例的直接,明确的答案。我很少知道 ** 2009 ** 中有一个会从那里链接到那里。

这是一个编码示例:

#include <iostream>
using namespace std;

int main() {
    float x = 0.1 * 7;
    if (x == 0.7)
        cout << "TRUE. \n";
    else
        cout << "FALSE. \n";

    return 0;
}

这导致FALSE。但是,当我输出x时,确实输出为0.7。解释

4 个答案:

答案 0 :(得分:7)

请阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

首先,0.1double类型的文字。 IEEE 754双精度中最接近的可表示值为:

0.1000000000000000055511151231257827021181583404541015625

如果将其乘以7,IEE 754单精度中最接近的可表示值(因为您将其存储在float中)是:

0.699999988079071044921875

正如您所看到的那样,几乎 0.7,但并不完全。然后将其转换为double进行比较,最后比较以下两个值:

0.699999988079071044921875 == 0.6999999999999999555910790149937383830547332763671875

当然评估为false

答案 1 :(得分:1)

这是因为数字以二进制形式存储。在二进制中,你无法用有限多的位置精确地表示分数.1或.7,因为它们具有二进制的重复扩展。类似1/2的东西可以用表示.1来表示,但十进制的.1例如是.0001100110011 ....所以,当你切断这个数字时,你肯定会有舍入错误。

答案 2 :(得分:0)

==运算符永远不应该比较双打和浮点数。数字不准确地存储在存储器中,因为在二进制中它们不必具有有限的表示(例如0.1)。

你会在这里看到它:

#include <iostream>
using namespace std;

int main() {
    float x = 0.1 * 7;
    cout << x-0.7;
    return 0;
}

差异不是零,而是非常接近于零的东西。

答案 3 :(得分:0)

与每种数据类型一样,float表示为二进制数。有关确切表示,请参见此处:http://en.wikipedia.org/wiki/IEEE_floating_point

手动将十进制数转换为浮点数时,首先必须将其转换为固定点数。

将0.7转换为基数2(二进制):

0.7 = 0.101100110011 ......

如您所见,它在逗号后面有无穷大的数字,因此当将其表示为float数据类型时,某些数字将被截断。当将其转换回十进制时,这导致数字不完全为0.7。

在您的示例中,乘法产生的数字与文字“0.7”不同。

解决此问题:比较浮点数的相等性时使用epsilon:

if (x < 0.71f && x > 0.69f)