2013-05-15 121 views
4

对于以下程序:C++不正确浮点算术

#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 

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

+0

猜猜他们最大的精度是多少。 – chris

+0

你认为浮点运算能做什么? –

+0

好吧,我张贴在我的问题,他们最大在10^-16,我期望得到我最后列出的那种输出,虽然基于这些问题,我猜你们会指出我正在重载数据类型,我会因为问这个问题而感到愚蠢。 –

回答

6

即使使用浮点数或双精度浮点数,计算机也无法表示很多数字。 1/3或.3重复,就是其中的一个数字。所以它只是尽其所能,这是你得到的结果。

请参阅http://floating-point-gui.de/或谷歌浮动精度,这里有很多关于这个问题的信息(包括许多SO问题)。

要回答你的问题 - 是的,这是浮子班和双班的固有限制。一些数学程序(MathCAD,可能是Mathematica)可以做“符号”数学,它允许计算“正确的”答案。在很多情况下,即使在真正复杂的计算中,也可以管理舍入误差,例如,前6到8位小数位是正确的。然而,相反的情况也是如此 - 天真的计算可以被构建,返回非常不正确的答案。

对于像整数分割这样的小问题,你会得到一个不错的小数位精度(可能是4-6位)。如果你使用双精度浮点数,那么可能会达到8.如果你需要更多...嗯,我会开始质疑你为什么要这么多小数位。

+0

感谢您的信息,以及为什么我需要这么多小数位是因为我正在一个项目欧罗项目,我需要识别重复小数长系列。这就是为什么直到今天我从不担心精度。 –

+0

@eldersouth在这种情况下,这是一个只涉及整数和整数算术的问题。使用浮点数是错误的(具有任意精度整数的实际理性可能是一种选择,但普通机器“int”算法是最简单和最好的方法)。 –

+2

我很确定,通过使用“长分隔”方法可以完成识别重复序列,就像手工将12341除以73所得到的一样(或将10除以7,等等)[编辑:和这个可以在整数数学中完成] –

2

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

+0

由于某种原因,他的输出精确到〜53位,但您的观点是正确的。 –

5

首先,因为你的代码做1.0/a,它给你double1.0double值,1.0ffloat)为C的规则++(和C)一直延伸较小的类型,如果操作数较大的一个的操作是不同的大小(所以,int + char使char成为int之前添加的值,long + int将使int长等等,等等)。

第二个浮点值具有“数字”的设定位数。浮点数是23位(+ 1'隐藏'位),双精度浮点数是52位(+1)。然而,如果我们使用十进制数字表示,每位可以获得大约3位数字(确切地说:log2(10)),所以23位数字给出大约7-8位数字,53位数字大约16-17位数字。其余部分仅仅是由于数字的最后几位不是在晚上转换成十进制数时引起的“噪声”。

要具有无限精度,我们必须将该值存储为分数,或者具有无限数量的位。当然,我们可以有其他有限的精度,比如100位,但我相信你也会抱怨,因为在它出现“错误”之前,它只会有另外15个数字。

+0

@MooingDuck:其实我从记忆中拿走了他们,这显然也搞砸了。现在修复。 –

+0

其余部分不完全是噪音。浮动应该有6个准确的数字,然后下一个数字通常是准确的,有8%的几率被关闭。 (除非当然它会翻转,导致前面的数字四舍五入)。 –

+0

@MooingDuck:不,我的意思是说,当你把最后一个十进制数字是“准确的”时,下一个将只提供一个部分数字,其余的数字是由于试图不断地乘数/转换成小数点[并且可能会累积先前部分计算中的误差] –