6

对于以下程序:

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    for (float a = 1.0; a < 10; a++)
        cout << std::setprecision(30) << 1.0/a << endl;
    return 0;
}

我收到以下输出:

1
0.5
0.333333333333333314829616256247
0.25
0.200000000000000011102230246252
0.166666666666666657414808128124
0.142857142857142849212692681249
0.125
0.111111111111111104943205418749

这绝对不适合低位数字,特别是对于 1/3、1/5、1/7 和 1/9。事情在 10^-16 左右开始出现问题,我希望看到的结果更像:

1
0.5
0.333333333333333333333333333333
0.25
0.2
0.166666666666666666666666666666
0.142857142857142857142857142857
0.125
0.111111111111111111111111111111

这是浮点类中的继承缺陷吗?有没有办法克服这个并进行适当的划分?是否有用于进行精确十进制运算的特殊数据类型?在我的例子中,我只是在做一些愚蠢或错误的事情吗?

4

3 回答 3

6

即使您使用浮点数或双精度浮点数,计算机也无法表示很多数字。1/3 或 0.3 重复是这些数字之一。所以它只是尽力而为,这就是你得到的结果。

请参阅http://floating-point-gui.de/或 google float precision,关于这个主题有大量信息(包括许多 SO 问题)。

回答您的问题 - 是的,这是 float 类和 double 类的固有限制。一些数学程序(MathCAD,可能是 Mathematica)可以进行“符号”数学运算,从而可以计算出“正确”的答案。在许多情况下,可以管理舍入误差,即使在非常复杂的计算中,前 6-8 位小数是正确的。然而,相反的情况也是如此——可以构建返回非常不正确的答案的幼稚计算。

对于整数除法等小问题,您将获得相当多的小数位精度(可能是 4-6 位)。如果你使用双精度浮点数,那可能会上升到 8。如果你需要更多......好吧,我会开始质疑你为什么想要那么多小数位。

于 2013-05-15T20:51:53.647 回答
6

首先,由于您的代码确实如此1.0/a,它会为您提供double( 1.0is a doublevalue, 1.0fis float),因为如果操作的操作数大小不同(因此,int+在添加值之前将charchar变为 a , +将变为long 等)。intlongintint

第二个浮点值具有“数字”的固定位数。在浮点数中,这是 23 位(+ 1“隐藏”位),在双精度中是 52 位(+1)。然而,每比特大约有 3 位数字(确切地说:log2(10),如果我们使用十进制数字表示),所以 23 位数字大约有 7-8 位数字,53 位数字大约有 16-17 位数字。余数只是由数字的最后几位在转换为十进制数时不均匀引起的“噪音”。

为了获得无限的精度,我们要么将值存储为分数,要么拥有无限数量的位。当然,我们可以有一些其他的有限精度,比如 100 位,但我相信你也会抱怨这一点,因为在它“出错”之前只有 15 位左右的数字。

于 2013-05-15T20:57:41.310 回答
2

浮点数只有这么高的精度(准确地说是 23 位)。如果您真的想看到“0.333333333333333333333333333333”输出,您可以创建一个自定义“分数”类,分别存储分子和分母。然后,您可以完全准确地计算任何给定点的数字。

于 2013-05-15T20:51:57.963 回答