Floating point 浮点不准确性示例

Floating point 浮点不准确性示例,floating-point,floating-accuracy,Floating Point,Floating Accuracy,你如何向仍然认为计算机是无限明智和准确的新手程序员和外行解释浮点不准确 你有没有一个最喜欢的例子或轶事比一个精确但枯燥的解释更能让人理解你的想法? 这在计算机科学课上是如何教授的?基本上,人们在使用浮点数时会遇到两个主要的陷阱 规模问题。每个FP数字都有一个指数,它决定了数字的整体“规模”,因此您可以表示非常小的值,也可以表示非常大的值,尽管您可以为此投入的位数是有限的。添加两个不同刻度的数字有时会导致较小的数字被“吃掉”,因为无法将其放入较大的刻度 PS> $a = 1; $b = 0.

你如何向仍然认为计算机是无限明智和准确的新手程序员和外行解释浮点不准确 你有没有一个最喜欢的例子或轶事比一个精确但枯燥的解释更能让人理解你的想法?

这在计算机科学课上是如何教授的?

基本上,人们在使用浮点数时会遇到两个主要的陷阱

  • 规模问题。每个FP数字都有一个指数,它决定了数字的整体“规模”,因此您可以表示非常小的值,也可以表示非常大的值,尽管您可以为此投入的位数是有限的。添加两个不同刻度的数字有时会导致较小的数字被“吃掉”,因为无法将其放入较大的刻度

    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

    类似地,二进制分数也适用于表示二分之一、四分之一、八分之一等,但像十分之一这样的东西会产生无限重复的二进制数字流

  • 然后还有另一个问题,尽管大多数人不会偶然发现,除非他们在做大量的数字工作。但是,这些人已经知道了这个问题。由于许多浮点数仅仅是精确值的近似值,这意味着对于实数r的给定近似值f,可以有无穷多个实数r1、r2、。。。映射到完全相同的近似值。这些数字在一定的区间内。假设rmin是r的最小可能值,导致f和rmax,这是r的最大可能值,那么你得到了一个区间[rmin,rmax],这个区间中的任何数字都可以是你的实际数字r

    现在,如果你对这个数字进行加、减、乘等运算,你就会失去精度。每个数字都只是一个近似值,因此您实际上是在按间隔执行计算。结果也是一个区间,近似误差只会越来越大,从而扩大区间。你可以从计算中得到一个数字。但考虑到原始操作数的精度和计算造成的精度损失,这仅仅是可能结果间隔中的一个数字

    这种事情被称为,至少对我来说,它是我们大学数学课程的一部分


  • 基本上,人们在使用浮点数时会遇到两大陷阱

  • 规模问题。每个FP数字都有一个指数,它决定了数字的整体“规模”,因此您可以表示非常小的值,也可以表示非常大的值,尽管您可以为此投入的位数是有限的。添加两个不同刻度的数字有时会导致较小的数字被“吃掉”,因为无法将其放入较大的刻度

    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

    类似地,二进制分数也适用于表示二分之一、四分之一、八分之一等,但像十分之一这样的东西会产生无限重复的二进制数字流

  • 然后还有另一个问题,尽管大多数人不会偶然发现,除非他们在做大量的数字工作。但是,这些人已经知道了这个问题。由于许多浮点数仅仅是精确值的近似值,这意味着对于实数r的给定近似值f,可以有无穷多个实数r1、r2、。。。映射到完全相同的近似值。这些数字在一定的区间内。假设rmin是r的最小可能值,导致f和rmax,这是r的最大可能值,那么你得到了一个区间[rmin,rmax],这个区间中的任何数字都可以是你的实际数字r

    现在,如果您对该nu执行计算