如何处理无限重复的数字作为小数?

11
当除法的结果是一个无限重复的数字时,这个数字显然会被截断以适应小数的尺寸。所以像1/3这样的东西变成了0.3333333333333333333。如果我们将这个数字乘以3,我们将得到类似于0.999999999999999999而不是1的结果,如果保留了分数的真实值,我们会得到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进行相等比较时,这会导致问题。如果不失精度,它们将相等,但在这种情况下,比较结果会为false。

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


@nathanhayfield 看起来你错过了问题的最后一句话。 - Danny Beckett
然而,这仍然是通常的做法,可以原地修改,也可以使用一个内部带有边距或让你指定边距的函数(从可读性角度来看这种方式更加优雅,但概念相同)。 (如果您要向用户显示结果,请不要忘记将浮点数四舍五入为可读的内容。没有人想看到他们欠$1.99999999999。是的,我见过几次。) - neminem
2
这是数字计算中一个旧问题,众所周知。 - Sina Iravanian
2
这个怎么样:http://www.codeproject.com/Articles/11971/Fractions-in-C - Dilshod
当我遇到这种情况时,我会缩小实际问题的范围并解决它,而不是寻求一个关于十进制处理的通用理论。例如:https://dev59.com/bGHVa4cB1Zd3GeqPjhxw - Chris Moschini
4个回答

6
这是一个非常古老且广泛知晓的数值计算问题。您已经说过您正在寻找一种解决方案,而不是为每个比较定义一些误差范围。我想到的一个方法是首先在内存中构建数学表达式树,然后进行最后的计算。有了这个,我们可以在计算之前使用一些已知规则进行简化。例如:
  • 如果分数的分子和分母相等且均不为零,则删除
  • 一个数的平方的平方根即为其本身
  • ...
因此,我们可以将 1/3 存储为 Fraction(1, 3) 的实例,而不是以 decimal/double 值的形式存储它,该值等于 0.33333...。接着,我们可以像这样定义所有其他表达式来构建一个表达式而不是进行计算。最后,我们可以先使用上述规则简化表达式,然后再计算结果。
我搜索了一下网络,没有找到可以完成这项任务的库,但我确信可以在其他语言/平台或甚至 .NET 中找到一些库。
请注意,上述方法最终只能得出更好的结果,但并不能解决数值计算固有的问题。

像Waterloo Maple或Mathematica这样的软件包当然可以做到这一点。但我不知道有任何.NET库可以做到这一点。 - Eric Lippert
我找不到任何.NET库,最终只能自己制作具备基本功能的库。 - GBleaney

2

正如您所提到的,使用浮点数进行计算的结果必须“适应”浮点表示法。这就是为什么精确比较不是一个好主意 - 需要一定的容差。因此,应该使用 Math.Abs(x - y) < tolerance而不是x == y


1
欢迎来到浮点数算术的痛苦。
当然,你真正想要的是一个有理数类和库。这里有一个C#的起点,但我不知道它有多完整(可能不太完整):

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

在C/C++中有一些相关内容,但是不确定它们的实用性和完整性。

对于浮点数:

可以查看一些资源。首先,David Goldberg的经典之作《计算机科学家应该知道的浮点运算知识》。以下是摘要:

许多人认为浮点运算是一门神秘的学科。这相当令人惊讶,因为浮点运算在计算机系统中无处不在:几乎每种语言都有浮点数据类型;从个人电脑到超级计算机,都有浮点加速器;大多数编译器将不时地编译浮点算法;几乎每个操作系统都必须响应浮点异常,如溢出。本文介绍了与计算机系统设计师直接相关的浮点方面的教程。它从浮点表示和舍入误差的背景开始,继续讨论IEEE浮点标准,并以计算机系统构建者如何更好地支持浮点为例进行了总结。

您可以从多个地方免费下载编辑过的版本:

此外,原版应该很容易在那座有所有书的大砖建筑物中获取。完整引用如下:

David Goldberg. 1991. 每个计算机科学家都应该了解的浮点运算知识。ACM Comput. Surv.23,1(1991年3月),5-48.DOI=10.1145/103162.103163 http://doi.acm.org/10.1145/103162.103163

然后查看以下资源:


Microsoft Solver Foundation 随附有一个 Rational 类。 - Eric Lippert

0

如果按照我的注释方式进行,将其存储到数据库中也不会有问题。您可以使用分数类型在数据库中存储它。请参见UDT。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接