浮点不准确的例子 [英] Floating point inaccuracy examples

查看:145
本文介绍了浮点不准确的例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你如何解释浮点不准确的新鲜程序员和外行谁仍然认为电脑是无限的明智和准确?

你有一个最喜欢的例子或轶事似乎得到的想法跨越好一个精确而干燥的解释?

在计算机科学课上讲授的是什么?

解决方案

基本上是两个主要的陷阱,人们用浮点数绊倒。


  1. 规模问题。每个FP编号都有一个指数,它决定了数字的整体比例,因此您可以表示非常小的值或真正的大数值,尽管您可以为此设置的位数是有限的。添加两个不同比例的数字有时会导致较小的一个被吃掉,因为没有办法将它放到较大的比例中。

      PS> $ a = 1; $ b = 0.0000000000000000000000001 
    PS>写主机a = $ a b =
    $ b a = 1 b = 1E-25
    PS> $ a +
    $ b 1

    作为这种情况的一个比喻,游泳池和一茶匙的水。两者的尺寸都非常不同,但是您可以轻松掌握它们的粗略程度。然而,把茶匙倒入游泳池,会让你仍然有一个大概的游泳池。如果学习这个的人有指数记号的麻烦,也可以使用 1 100000000000000000000 左右的值。)


  2. 然后是二进制与十进制表示的问题。像 0.1 这样的数字不能用有限的二进制数字来表示。一些语言掩盖了这一点:$ b​​
    $ b

      PS> {0:N50}-f 0.1 
    0.10000000000000000000000000000000000000000000000000

    但是你可以放大通过反复添加数字来表示错误:

      PS> $ sum = 0; for($ i = 0; $ i -lt 100; $ i ++){$ sum + = 0.1}; $ sum 
    9,99999999999998

    我想不出一个好的比喻来正确解释这个,虽然。它基本上是一个同样的问题,为什么你只能用十进制来表示 1 / 3 ,因为要得到确切的值,你需要在小数部分末尾无限地重复3 。

    同样,二进制分数对于代表半数,季度,八分之一等是好的,但是像十分之一这样的事情会产生无限重复的二进制数字流。 r ,可以有无限多的实数 r 1 r 2 ,...映射到完全相同的近似值。这些数字在一定的时间间隔内。假设 r min r 的最小可能值,它会导致 f r max 这是可能的 r 的最大可能值,那么你得到了一个间隔[ r min r max ],其中间隔中的任何数字都可以是您的实际数字。

    现在,如果你对这个数字进行计算 - 加,减,乘等等 - 你会失去精度。每个数字只是一个近似值,因此实际上是使用间隔执行计算。结果也是一个时间间隔,近似误差只会变大,从而扩大间隔。你可以从这个计算中得到一个单一的数字。但是,这只是可能的结果间隔中的一个数字,要考虑到原始操作数的精度以及由于计算造成的精度损失。

    这种事情叫做区间算术,至少对我而言这是我们大学数学课程的一部分。



How do you explain floating point inaccuracy to fresh programmers and laymen who still think computers are infinitely wise and accurate?
Do you have a favourite example or anecdote which seems to get the idea across much better than an precise, but dry, explanation?
How is this taught in Computer Science classes?

解决方案

There are basically two major pitfalls people stumble in with floating-point numbers.

  1. The problem of scale. Each FP number has an exponent which determines the overall "scale" of the number so you can represent either really small values or really larges ones, though the number of digits you can devote for that is limited. Adding two numbers of different scale will sometimes result in the smaller one being "eaten" since there is no way to fit it into the larger scale.

    PS> $a = 1; $b = 0.0000000000000000000000001
    PS> Write-Host a=$a b=$b
    a=1 b=1E-25
    PS> $a + $b
    1
    

    As an analogy for this case you could picture a large swimming pool and a teaspoon of water. Both are of very different sizes, but individually you can easily grasp how much they roughly are. Pouring the teaspoon into the swimming pool, however, will leave you still with roughly a swimming pool full of water.

    (If the people learning this have trouble with exponential notation, one can also use the values 1 and 100000000000000000000 or so.)

  2. Then there is the problem of binary vs. decimal representation. A number like 0.1 can't be represented exactly with a limited amount of binary digits. Some languages mask this, though:

    PS> "{0:N50}" -f 0.1
    0.10000000000000000000000000000000000000000000000000
    

    But you can "amplify" the representation error by repeatedly adding the numbers together:

    PS> $sum = 0; for ($i = 0; $i -lt 100; $i++) { $sum += 0.1 }; $sum
    9,99999999999998
    

    I can't think of a nice analogy to properly explain this, though. It's basically the same problem why you can represent 1/3 only approximately in decimal because to get the exact value you need to repeat the 3 indefinitely at the end of the decimal fraction.

    Similarly, binary fractions are good for representing halves, quarters, eighths, etc. but things like a tenth will yield an infinitely repeating stream of binary digits.

  3. Then there is another problem, though most people don't stumble into that, unless they're doing huge amounts of numerical stuff. But then, those already know about the problem. Since many floating-point numbers are merely approximations of the exact value this means that for a given approximation f of a real number r there can be infinitely many more real numbers r1, r2, ... which map to exactly the same approximation. Those numbers lie in a certain interval. Let's say that rmin is the minimum possible value of r that results in f and rmax the maximum possible value of r for which this holds, then you got an interval [rmin, rmax] where any number in that interval can be your actual number r.

    Now, if you perform calculations on that number—adding, subtracting, multiplying, etc.—you lose precision. Every number is just an approximation, therefore you're actually performing calculations with intervals. The result is an interval too and the approximation error only ever gets larger, thereby widening the interval. You may get back a single number from that calculation. But that's merely one number from the interval of possible results, taking into account precision of your original operands and the precision loss due to the calculation.

    That sort of thing is called Interval arithmetic and at least for me it was part of our math course at the university.

这篇关于浮点不准确的例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆