是“计算器错误”吗?代码问题?

发布于 2024-10-07 11:38:33 字数 293 浏览 5 评论 0原文

我在很多博客文章中都看到过这个错误: http://atifsiddiqui.blogspot.com/2010/11/windows-calculator -bug.html

这个错误是代码错误还是数学不精确?

我想知道这是否真的是一个错误,它是如何多年来未被发现的?

我应该注意什么以确保它不会在我的自定义计算器程序中发生。

I have seen this bug in many blog posts:
http://atifsiddiqui.blogspot.com/2010/11/windows-calculator-bug.html

Is this bug a code bug or a mathematical imprecision ?

I am wondering if its really a bug, How it got undetected for years ?

What should I take care to make sure that it doesn't happen in my custom caculator program.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

帝王念 2024-10-14 11:38:33

是的,这是一个错误。它有一个技术解释(外行人很难接受)这一事实并不能免除它是一个错误。如果这不是一个错误,那么您要么认为(正如我们有时所做的那样)“这是一个功能”,要么认为这是系统的限制。

为了解决这个问题,我建议您将每个结果四舍五入到可接受的精度水平,以消除非常小的错误。正如其他答案所暗示的那样,问题是在您的计算器中,“4”的平方根不是“2”,而是一个非常接近 2 的数字。要解决此问题,请将结果四舍五入到小数点后 10、20、30 位或只要你能负担得起。

我认为任何计算器引擎都应该具有基本的精度水平,该精度水平超出可访问的精度水平足够大的裕度,以便用户无法访问浮点运算的限制。如果您选择这条路径,您将失去一种形式的“准确性”,但您只需声明您的计算器精确到小数点后 n 位。这是完全可以接受的,特别是如果它解决了这个问题。

但这其实没什么大不了的,不是吗?


顺便说一句,我曾经开发过一个金融应用程序,其中供应商提供了一些应该计算一些复利利率的软件。他们的计算总是错误的。他们认为这是“由于浮点运算”,并试图在这个问题上教育我;但他们的算法还差得很远。当对美元金额进行复利时,我们总是在每次迭代(日、周、月、年或其他)后对总数进行四舍五入。根据具体情况,它可能四舍五入到最接近的美元、最接近的美分或最接近的百分之一美分 - 但它是一个可量化的金额,我们从不逐年复利百万分之一美分。如果您想避免本质上的计算舍入误差,则应采用这种方法。

Yes, it's a bug. The fact that it has a technical explanation (which is hardly acceptable to the layperson) does not absolve it from being a bug. If it's not a bug then you are either arguing that - as we all do on occasion - "it's a feature", or that it is a limitation of the system.

To resolve it I'd suggest you round every result to an acceptable precision level to remove the very small error. As the other answers suggest, the problem is that in your calculator the square root of '4' is not '2', but rather a number very close to 2. To resolve this round the result to 10, 20, 30 decimal places or whatever you can afford.

I'd argue that any calculator engine should have an underlying level of precision that exceeds the accessible level of precision by a large enough margin so that the user is not able to access the limits of float point arithmetic. You'll lose one form of 'accuracy' if you take this path, but you simply state that your calculator is accurate to n decimal places. That's more than acceptable especially if it resolves this issue.

However it's not really a big deal, is it?


As an aside, I once worked on a financial application where a vendor provided some software which was supposed to compute some compounding interest rates. Their calculations were always off. They argued that it was 'due to floating point arithmetic' and tried to educate me on the issue; but their algorithm was way off. When compounding interest rates on dollar amounts, we always round the total after each iteration (day, week, month, year or whatever). Depending on the situation it may round to the nearest dollar, nearest cent, or nearest 100th of a cent - but it is a quantifiable amount, and we never compound millionths of a cent from year to year. This is the approach that you should take if you want to avoid what is essentially a computation rounding error.

狼亦尘 2024-10-14 11:38:33

我同意 @Kirk Broadhurst 的观点,即这在技术上是一个错误,因为 sqrt(4)-2 的结果严格为 0,而 Calc 给出了不同的(尽管非常接近)结果。事实上,我们通常可以忍受这种不精确性,但在这里无关紧要。严格来说,程序员应该寻求不同的方法来解决此类问题。

恕我直言,这里很多人没有看到的是 4 和 2 可以用 IEEE 浮点格式精确表示。作为 2 的自然幂使其可以表示无限精度,因此指责 FP 格式的争论也无关紧要。问题来自 sqrt() 函数算法,而不是 FP 存储格式。

I agree with @Kirk Broadhurst that this is technically a bug, as the result of sqrt(4)-2 is strictly 0, while Calc gives a different (albeit extremely close) result. The fact that usually we can live with this imprecision is irrelevant here. Strictly speaking, the programmers should have seeked different approaches for solving this kind of problems.

IMHO, what many people here fail to see is that 4 and 2 are precisely representable in IEEE floating point format. Being a natural power of 2 makes it representable to infinite precision, so the arguments blaming the FP format are irrelevant as well. The problem comes from the sqrt() function algorithm and not from the FP storage format.

回首观望 2024-10-14 11:38:33

正如其他人所说,这不是一个错误,而是与计算机内部表示浮点数和处理浮点运算的方式有关。事实证明,你和我并不以浮点思维数学,但计算机可以。而“浮点数”指的是二进制小数点,而不是十进制小数点。

它返回的数值实际上极其接近0(我想我们都同意这是“正确的”十进制答案)。发生的情况是 sqrt 函数本身返回一个非常接近 2 的数字,但由于浮点的限制,该数字无法在内部存储为精确 2类型。 输出是数字“2”,因为计算器只是出于显示目的对其进行四舍五入,知道“2”是您期望的答案。但是,当您从内部存储的 sqrt(4) 表示形式中减去 2 时,您不会得到精确的 0,因为内部存储的数字并不精确为 2。

每个程序员都应该真正阅读 “每个计算机科学家应该了解浮点运算”,解释了这种行为(特别是有关“精度”和“二进制到十进制转换”的部分)以及有关计算机内部将数字表示为浮点类型的方式的许多其他令人难以置信的细节。

As others have said, this is not a bug, but instead related to the way computers represent floating point numbers internally and handle floating point arithmetic. It turns out that you and I don't think in floating point math, but computers do. And that "floating point" refers to a binary point, rather than a decimal one.

The numerical value that it's returning is in fact extremely close to 0 (which I think we can all agree is the "correct" decimal answer). What happened is that the sqrt function itself returned a number extremely close to 2, but this number couldn't be stored internally as exactly two because of the limitations of the floating point type. The output was the number "2" because Calculator just rounded it off for display purposes, knowing that "2" was the answer you expected. But then when you subtract 2 from that internally stored representation of sqrt(4), you don't get exactly 0, because the number stored internally was not exactly 2.

Every programmer should really read "What Every Computer Scientist Should Know About Floating-Point Arithmetic", which explains this behavior (particularly, the sections on "Precision" and "Binary to Decimal Conversion") and lots of other mind-boggling details about the way that computers represent numbers internally as floating point types.

掐死时间 2024-10-14 11:38:33

不是错误(计算机就是这样工作的!)。 SO 有很多关于这个主题的问题。例如,搜索“JavaScript math bad”。

有经验的计算机用户还应该认识到 -8.1648465955514287168521180122928e-39 实际上与零相同。

如果您想避免类似的情况,可以在将每个结果转换为字符串时对每个结果进行四舍五入。 -8.1648465955514287168521180122928e-39 将四舍五入为 0。但是,如果您正在编写一个非常高级的计算器,能够使用普朗克常数(如果您这样做,普朗克常数将被视为等于零),则这不起作用,这很糟糕)。一个非常好的选择是使用符号数学,但是编写计算器不需要几分钟,而是数月/数年......

This is not a bug (computers work this way!). There are a lot of questions on this topic at SO. Search for "JavaScript math broken", for instance.

An experienced computer user should also recognize that -8.1648465955514287168521180122928e-39 is practically the same as zero.

If you want to avoid things like this, you can round every result when converting it to a string. -8.1648465955514287168521180122928e-39 would be rounded to 0. This, however, doesn't work if you are writing a very advanced calculator, able to work with for instance Planck's constant (if you did this, Planck's constant would be considered equal to zero, which is bad). A very good alternative is to work with symbolic math, but then it wouldn't take minutes to write a calculator, but months/years...

╰沐子 2024-10-14 11:38:33

这是一个常见的浮点问题。例如,如果您以 1/3 aqnd 为例,然后乘以浮点型 3,则不会精确返回 1,而是 0.9999999999999999999999< /code> 或 1.000000000000000000001。 Windows计算器使用一些算法来尝试最小化像我刚刚解释的情况,但它们可能没有处理所有特殊情况......

这不完全是一个错误,更多的是可用性问题,因为它们处理了一些有案例但不是全部..

Its a common floating point problem. If you take for example 1/3 aqnd then multiply by 3 in floating point you wont get exactly 1 back, but 0.9999999999999999999999, or 1.000000000000000000001. Windows calculator used some algorithm to try and minimize cases like the i just explained, but it might be that they didn't handle all special cases....

Its not exactly a bug, more a usability problem, as they handle some of the cases but not all..

此刻的回忆 2024-10-14 11:38:33

它比普通浮点问题稍微复杂一些,因为 Calc 实际上使用任意精度数学。但至关重要的是,它似乎只对基本操作使用无限精度,如 Raymond 所述陈

如今,Calc 的内部计算对于基本运算(加法、减法、乘法、除法)以无限精度完成,对于高级运算(平方根、超越运算符)以 32 位精度完成。

所以大概平方根实际上会产生一个非常接近的值,但不是 2,而是显示为 2,在精确减法之后,您留下一个非常接近 0 的数字,但不显示为 0,这是否是一个错误?取决于。

It's slightly more complicated than the normal floating point issues as Calc actually uses arbitrary precision mathematics. Crucially however it only seems to use infinite precision for basic operations, as stated by Raymond Chen

Today, Calc's internal computations are done with infinite precision for basic operations (addition, subtraction, multiplication, division) and 32 digits of precision for advanced operations (square root, transcendental operators).

So presumably the square root actually results in a value very close to, but not 2 but which is displayed as 2, after the precise subtraction you are left with a very close to 0 number which is not displayed as 0, is this a bug though? depends.

亚希 2024-10-14 11:38:33

纯粹猜测,我会说这是因为计算器没有得到精确的 2 作为平方根的结果(取决于它如何计算根)。但当结果远离零时,它只会对显示进行四舍五入。但当数字接近零时,它会显示准确的结果。

对于自己的计算器,您可能不会因为没有如此高的精度而获得这样的结果(在使用编程语言提供的正常数学功能时通常没有这种精度)。

With pure guessing, I would say it's because the calculator doesn't get exactly 2 as the result of the square root (depending on how it calculates the root). But when the result is away from zero, it simply rounds the display. But when the number is near zero, it shows the exact result.

For an own calculator, you probably won't get such results by simply not having such a high accuracy (which you usually don't have when using normal math features a programming language gives).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文