我在很多博文中看到过这个错误: http://atifsiddiqui.blogspot.com/2010/11/windows-calculator-bug.html
这个错误是代码错误还是数学上的不精确?
我想知道它是不是真的是一个错误,它多年未被发现?
我应该注意什么,以确保它不会发生在我的自定义计算器程序中。
答案 0 :(得分:6)
是的,这是一个错误。事实上,它有一个技术性的解释(外行人难以接受)并不能免除它成为一个错误。如果它不是一个错误,那么你要么在争论 - 正如我们所有人偶尔做的那样 - “它是一个特征”,或者它是系统的限制。
要解决此问题,我建议您将每个结果舍入到可接受的精度级别,以消除非常小的错误。正如其他答案所示,问题是在你的计算器中,'4'的平方根不是'2',而是一个非常接近2的数字。为了解决这个问题,将结果舍入到10,20,30小数点或无论你能买得起什么。
我认为任何计算器引擎都应该具有超出可访问精度水平的基础精度水平,以及足够大的余量,以便用户无法访问浮点运算的限制。如果采用此路径,您将失去一种“准确性”形式,但您只是声明您的计算器精确到小数点后n位。如果能解决这个问题,那就更容易接受了。
然而,这不是什么大不了的事,是吗?
顺便说一句,我曾经在一个金融应用程序上工作过,供应商提供了一些应该计算一些复利率的软件。他们的计算总是关闭。他们认为这是“由于浮点运算”并试图教育我这个问题;但他们的算法很遥远。在对美元金额进行复利时,我们总是舍入每次迭代后的总数(日,周,月,年或其他)。根据具体情况,它可以四舍五入到最接近的美元,最近的分数,或最近的百分之一 - 但这是一个可量化的数额,我们从来没有复合百万分之一的年份。如果您想避免本质上是计算舍入错误,则应采取这种方法。
答案 1 :(得分:3)
正如其他人所说,这不是一个错误,而是与计算机在内部表示浮点数并处理浮点运算的方式有关。事实证明你和我都不认为在浮点数学,但计算机。而“浮点”指的是二进制点,而不是十进制点。
它返回的数值实际上非常接近于0(我认为我们都同意这是“正确的”十进制答案)。发生的事情是sqrt函数本身返回的数字极接近2,但由于浮点的限制,这个数字无法在内部存储为完全 2类型。 输出是数字“2”,因为计算器只是将其四舍五入用于显示目的,因为知道“2”是您所期望的答案。但是当你从内部存储的sqrt(4)
表示中减去2时,你得不到0,因为内部存储的数字并不完全是2。
每个程序员都应该阅读"What Every Computer Scientist Should Know About Floating-Point Arithmetic",这解释了这种行为(特别是关于“精度”和“二进制到十进制转换”的部分)以及许多关于计算机表示数字的方式的令人难以置信的细节内部作为浮点类型。
答案 2 :(得分:3)
我同意@Kirk Broadhurst的说法,这在技术上是一个错误,因为sqrt(4)-2的结果严格为0,而Calc给出了一个不同的(尽管非常接近)结果。通常我们可以忍受这种不精确的事实在这里是无关紧要的。严格地说,程序员应该寻求不同的方法来解决这类问题。
恕我直言,许多人在这里看不到的是4和2在IEEE浮点格式中可以精确表示。作为2的自然力量使其可以表示无限精度,因此归咎于FP格式的论点也是无关紧要的。问题来自sqrt()函数算法,而不是来自FP存储格式。答案 3 :(得分:2)
这是一个常见的浮点问题。如果你以1/3
aqnd为例,那么在浮点数乘以3
,你就不会得到1
,0.9999999999999999999999
或1.000000000000000000001
。 Windows计算器使用了一些算法来尝试最小化像我刚才解释的情况,但可能是他们没有处理所有特殊情况......
它不完全是一个错误,更像是一个可用性问题,因为它们处理了一些案例,但并非全部......
答案 4 :(得分:1)
这是不一个错误(计算机以这种方式工作!)。 SO上有很多关于这个主题的问题。例如,搜索“JavaScript math broken”。
有经验的计算机用户也应该认识到-8.1648465955514287168521180122928e-39几乎与零相同。
如果你想避免这样的事情,你可以在将每个结果转换为字符串时对其进行舍入。 -8.1648465955514287168521180122928e-39将四舍五入为0.但是,如果您正在编写一个非常高级的计算器,能够使用例如普朗克常数(如果您这样做,则普朗克常数将被视为等于零) ,这很糟糕)。一个非常好的选择是使用符号数学,但是编写计算器不需要几分钟,但是数月/年...
答案 5 :(得分:1)
它比普通的浮点问题稍微复杂一些,因为calc实际上使用了任意的精确数学。然而,正如raymond chen
所述,基本操作似乎只能使用无限精度今天,Calc的内部计算以基本操作(加法,减法,乘法,除法)的无限精度和高级操作(平方根,超越算子)的32位精度完成。
所以假设平方根实际上得到一个非常接近的值,但不是2,但显示为2,在精确减法后,你留下一个非常接近0的数字,不显示为0,这是虽然有虫子?取决于。
答案 6 :(得分:0)
纯粹的猜测,我会说这是因为计算器没有得到平方根的结果2
(取决于它如何计算根)。但是当结果远离零时,它只是围绕显示。但是当数字接近零时,它会显示确切的结果。
对于一个自己的计算器,你可能不会因为没有这么高的精度而得到这样的结果(当你使用编程语言提供的普通数学特性时,你通常没有这个结果)。