如何向初学者和普通人解释浮点数不精确性,他们仍然认为计算机是无限聪明和准确的?
你有没有一个特别喜欢的例子或轶事,它比精确但枯燥的解释更能让人理解这个概念?
计算机科学课程中如何教授这方面的知识?
如何向初学者和普通人解释浮点数不精确性,他们仍然认为计算机是无限聪明和准确的?
你有没有一个特别喜欢的例子或轶事,它比精确但枯燥的解释更能让人理解这个概念?
计算机科学课程中如何教授这方面的知识?
人们在处理浮点数时通常会遇到两个主要问题。
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.)
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.
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.
使用Python:
>>> 1.0 / 10
0.10000000000000001
解释一下为什么有些分数无法在二进制中精确表示。就像在十进制中有些分数(比如1/3)无法被精确表示一样。
1/(2^2)
。然后再用0.2尝试同样的事情,你会遇到问题,因为0.2在有限的二进制数中无法表示。 - Joachim Sauerprintf (" %.20f \n", 3.6);
不可思议地给出了
3.60000000000000008882
这是我的简单理解。
问题: 值0.45不能被浮点数准确地表示,会四舍五入为0.450000018。为什么会这样?
答案: 一个整数值45由二进制值101101表示。 为了得到值0.45,如果你能够取45 x 10^-2(= 45 / 10^2),那么它就是准确的。 但这是不可能的,因为你必须使用基数2而不是10。
因此,最接近10^2 = 100的值是128 = 2^7。你需要的总位数是9:6位用于值45(101101)+ 3位用于值7(111)。 然后,值45 x 2^-7 = 0.3515625。现在你有一个严重的不准确问题。0.3515625与0.45相差甚远。
我们如何改善这种不准确性?嗯,我们可以将值45和7更改为其他值。
如何计算460 x 2^-10 = 0.44921875。您现在使用了9位进行460的表示,以及4位进行10的表示。这样离目标值更接近了一些,但仍不够接近。然而,如果您最初期望的值是0.44921875,则可以获得精确匹配而无需进行近似计算。