Floating point 浮点不准确性示例
你如何向仍然认为计算机是无限明智和准确的新手程序员和外行解释浮点不准确 你有没有一个最喜欢的例子或轶事比一个精确但枯燥的解释更能让人理解你的想法?Floating point 浮点不准确性示例,floating-point,floating-accuracy,Floating Point,Floating Accuracy,你如何向仍然认为计算机是无限明智和准确的新手程序员和外行解释浮点不准确 你有没有一个最喜欢的例子或轶事比一个精确但枯燥的解释更能让人理解你的想法? 这在计算机科学课上是如何教授的?基本上,人们在使用浮点数时会遇到两个主要的陷阱 规模问题。每个FP数字都有一个指数,它决定了数字的整体“规模”,因此您可以表示非常小的值,也可以表示非常大的值,尽管您可以为此投入的位数是有限的。添加两个不同刻度的数字有时会导致较小的数字被“吃掉”,因为无法将其放入较大的刻度 PS> $a = 1; $b = 0.
这在计算机科学课上是如何教授的?基本上,人们在使用浮点数时会遇到两个主要的陷阱
PS> $a = 1; $b = 0.0000000000000000000000001
PS> Write-Host a=$a b=$b
a=1 b=1E-25
PS> $a + $b
1
作为这种情况的类比,你可以想象一个大游泳池和一茶匙水。两者的尺寸非常不同,但就个人而言,你很容易掌握它们的大致尺寸。然而,把茶匙倒进游泳池会让你的游泳池里仍然充满水
(如果学习这种方法的人在指数表示法方面有困难,也可以使用1
和1000000000000000000
左右的值。)0.1
这样的数字不能用有限的二进制数字精确表示。但有些语言掩盖了这一点:
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
类似地,二进制分数也适用于表示二分之一、四分之一、八分之一等,但像十分之一这样的东西会产生无限重复的二进制数字流>>> 1.0 / 10
0.10000000000000001
解释一些分数如何不能用二进制精确表示。就像有些分数(如1/3)不能在10进制中精确表示一样。这对于外行来说是如何解释的。计算机表示数字的一种方法是计算离散的单位。这些是数字计算机。对于整数,那些没有小数部分的数字,现代数字计算机计算2的幂:1,2,4,8,,,位置值,二进制数字,诸如此类。对于分数,数字计算机计算二的反幂:1/2,1/4,1/8。。。问题是许多数字不能用有限个逆幂的和来表示。使用更多的位值(更多的位)将提高这些“问题”数字的表示精度,但永远无法准确地得到它,因为它只有有限的位数。有些数字不能用无限位数来表示 打盹儿
好的,你想测量容器中的水的体积,你只有3个量杯:满杯、半杯和四分之一杯。在计算完最后一个满杯后,假设还有三分之一的杯子。但是你不能测量它,因为它不能完全填满任何可用杯子的组合。它不能填满半杯,四分之一杯的溢出物太小,无法填满任何东西。所以你有一个错误-1/3和1/4之间的差异。当你把这个误差与其他测量的误差结合起来时,这个误差就更加复杂了。告诉他们,base-10系统也有同样的问题 尝试将1/3表示为十进制,以10为基数。你不能完全做到这一点 因此,如果您编写“0.3333”,您将对许多用例有一个合理准确的表示 但是如果你把它移回一个分数,你会得到“3333/10000”,这和“1/3”不同 其他分数,如1/2,可以很容易地用以10为基数的有限十进制表示法表示:“0.5” 现在base-2和base-10面临着本质上相同的问题:它们都有一些无法精确表示的数字 虽然base-10在base-2中将1/10表示为“0.1”没有问题,但您需要一个以“0.000110011..”开头的无限表示
printf (" %.20f \n", 3.6);
难以置信地给予
3.600000000000008882如果将9999999.499999999转换成一个
浮点数,再转换回浮点数,就可以观察到一个可爱的数字怪圈