2013-04-18 53 views
9

当除法结果为无限重复的数字时,数字显然会被截断以适应小数点的大小。所以像1/3这样的东西变得像0.3333333333333333333。如果我们将这个数字乘以3,那么我们得到类似于0.999999999999999999而不是1的数据,就像我们将得到的数据的真实值保存一样。小数如何处理无限重复的数字?

这是从上小数MSDN文章的这一个代码示例:

decimal dividend = Decimal.One; 
decimal divisor = 3; 
// The following displays 0.9999999999999999999999999999 to the console 
Console.WriteLine(dividend/divisor * divisor); 

当值0.9999999999999999999与1相等相比,这导致一个问题。没有精度的损失,它们将是平等的,但当然在这种情况下,比较会导致错误。

人们通常如何处理这个问题?除了为每个比较定义一些误差外,是否还有更优雅的解决方案?

+0

@nathanhayfield看起来你错过了这个问题的最后一句话。 –

+0

尽管如此,那*就是这样做的一般方式,无论是在位置上,还是在函数内部都有空白的情况下,或者让你指定一个(这在可读性方面会更优雅,但概念相同)。(不要忘记,如果你曾经向用户展示过结果,也可能会看到一些可读的结果,没有人愿意看到他们欠$ 1.99999999999。是的,我已经看到过这种情况,好几次。) – neminem

+2

这是一个古老而知名的问题在数字计算 –

回答

5

这是一个非常古老且众所周知的数值计算问题。您已经表示您正在寻找一种解决方案,而不是为每次比较定义一些误差范围。我想到的一种方法是首先在内存中构建数学表达式树并最后进行计算。掌握这一点后,我们可以在进行计算之前使用一些已知规则进行一些简化。规则,例如:在一小部分的分子和分母

  • 删除相等数量的,如果他们不为零
  • 数字的平方的平方根是多少本身
  • ...

因此,不要将1/3存储在十进制/双精度值(等于0.33333)中......我们可以存储一个Fraction(1, 3)的实例。然后我们可以像这样定义所有其他表达式来构建表达式而不是进行计算。最后,我们可以先用上面的规则简化表达式,然后计算结果。

我在网上搜索了一下简单地找到了图书馆来做到这一点,但还没有找到。但我相信一些可以找到其他语言/平台,甚至.NET。

请注意,上述方法最终只会产生更好的结果,但并不能解决数值计算本质固有的问题。

+0

像Waterloo Maple或Mathematica这样的软件包可以做到这一点课程。我不知道任何.NET库。 –

+0

我找不到.NET库,最后我只是用自己所需的基本功能做了自己的工作。 – GBleaney

1

欢迎来到浮点算术的痛苦。

你真正想要的,当然是理性的数字类和图书馆。下面是一个在C#中的一个开始,虽然我不知道它是(可能不是很)如何完成:

http://www.codeproject.com/Articles/88980/Rational-Numbers-NET-4-0-Version-Rational-Computin

有一些在C/C++,但同样,不知道怎么有用/完成它们。

对于浮点数:

查看一些资源。首先,David Goldberg的经典着作是“每个计算机科学家应该知道的关于浮点运算的知识”。以下是摘要:

浮点算法被许多人视为深奥的主题。 这很令人惊讶,因为浮点在计算机系统中无处不在:几乎每种语言都有一个浮点数据类型;从PC到超级计算机的计算机具有浮点加速器;大多数编译器将被要求编译 时间的浮点算法; 几乎每个操作系统都必须响应浮点异常 (如溢出)。 本文介绍了一个关于浮点的教程,这些教程对计算机系统的设计者有直接的 影响。它以浮点数 表示和舍入错误的背景开始,继续讨论IEEE浮点标准,并结合计算机系统构建者如何更好地支持浮点的示例。

您可以从多个地方下载的文件,无偿的编辑版本:

此外,原本应该是容易在大砖头建筑,所有的书。全文引用为

David Goldberg。 1991年。每个计算机科学家应该知道的关于浮点数的算术运算。 ACM Comput。监测网。 23,1(1991年3月),5-48。 DOI = 10.1145/103162.103163 http://doi.acm.org/10.1145/103162.103163

然后看看这些资源:

+0

Microsoft Solver Foundation随附Rational类。 –

+0

@EricLippert:我不知道。谢谢! –

0

如果你有去我的方式commented然后将它存储到数据库中也不会成为问题。你可以用分数类型在数据库中存储它。请参阅UDT。

2

如上所述,使用浮点数的计算结果必须“拟合”到浮点表示中。这就是为什么精确比较不是一个好主意 - 需要一些宽容。所以应该使用x == yMath.Abs(x - y) < tolerance