代码之家  ›  专栏  ›  技术社区  ›  Humphrey Bogart

舍入误差?

  •  20
  • Humphrey Bogart  · 技术社区  · 16 年前

    在我的课程中,我被告知:

    连续值大约在内存中表示,因此使用浮点计算涉及舍入误差。这些是位模式中的微小差异;因此测试 e==f 是不安全的 e f 是漂浮物。

    参考Java。

    这是真的吗?我用比较语句 double S和 float 而且从未有过舍入问题。我从来没有读过类似的课本。虚拟机确实能解释这一点吗?

    9 回复  |  直到 16 年前
        1
  •  48
  •   Chris Vest    16 年前

    这是真的。

    它是浮点值在内存中以有限位数表示的固有限制。

    例如,这个程序打印“假”:

    public class Main {
      public static void main(String[] args) {
        double a = 0.7;
        double b = 0.9;
        double x = a + 0.1;
        double y = b - 0.1;
        System.out.println(x == y);
      }
    }
    

    与“==”进行精确比较不同的是,您通常决定某种程度的精度,并询问数字是否“足够接近”:

    System.out.println(Math.abs(x - y) < 0.0001);
    
        2
  •  24
  •   Jayan    13 年前

    这同样适用于Java,就像使用浮点的任何其他语言一样。它是硬件中浮点值表示的设计中固有的。

    有关浮点值的详细信息:

    What Every Computer Scientist Should Know About Floating-Point Arithmetic

        3
  •  7
  •   duffymo    16 年前

    是的,在基2中精确地表示0.1和在基10中精确地表示1/3是相同的。

        4
  •  4
  •   laginimaineb    16 年前

    这永远是真的。有些数字不能用浮点表示法精确表示。例如,考虑pi。在有限的存储空间中,如何表示一个具有无限位数的数字?因此,在比较数字时,你应该检查它们之间的差异是否小于一些epsilon。此外,还有几个类可以帮助您获得更高的精度,如bigdecimal和biginteger。

        5
  •  3
  •   Loren Pechtel    16 年前

    这是正确的。注意Java与它无关,问题是浮点数学中的固有问题。 任何 语言。

    你可以经常在课堂上解决问题,但在现实世界中是行不通的。有时它在教室里不起作用。

    很久以前在学校发生的一件事。一个入门班的老师布置了一个期末考试题,这对许多优秀的学生来说是一个非常愚蠢的问题——它不起作用,他们也不知道为什么。(我把这个看成是实验室助理,我不在班上。)最后一些人开始向我求助,一些调查揭示了这个问题:他们从未被教导浮点数学固有的不准确。

    现在,有两种基本的方法来解决这个问题,一种是蛮力方法(这种方法在这种情况下是偶然的,因为它每次都会犯同样的错误),另一种是更优雅的方法(它会犯不同的错误,但不起作用)。任何尝试过优雅方法的人都会在不知道为什么的情况下撞到砖墙。我帮了他们一大把,然后写了一篇评论,解释原因,如果他有问题,我会联系我。

    当然,下学期我听到了他关于这个的消息,我基本上用一个简单的小程序把整个部门搞得一团糟:

    10 X = 3000000
    20 X = X + 1
    30 If X < X + 1 goto 20
    40 Print "X = X + 1"
    

    不管系里每个老师怎么想,这个 威尔 终止。300万种子只是为了让它更快地结束。(如果你不知道基本原理:这里没有花招,只是耗尽了浮点数的精度。)

        6
  •  2
  •   Artur Soler    16 年前

    是的,正如其他答案所说。我想补充一下,我向您推荐这篇关于浮点精度的文章: Visualizing floats

        7
  •  2
  •   Nikolai Ruhe    16 年前

    大多数CPU(和计算机语言)使用IEEE754浮点运算。使用这个符号,在这个符号中有一些十进制数字没有精确的表示,例如0.1。所以如果你把1除以10,你就得不到确切的结果。在一行中执行多个计算时,误差相加。在python中尝试以下示例:

    >>> 0.1
    0.10000000000000001
    >>> 0.1 / 7 * 10 * 7 == 1
    False
    

    这不是你在数学上所期望的。

    顺便说一句: 关于浮点数的一个常见误解是,结果不精确,不能安全地处理。只有当你真正使用分数的时候才是这样。如果所有的数学都在整数域中,那么double和float与ints的作用完全相同,并且可以安全地进行比较。例如,它们可以安全地用作循环计数器。

        8
  •  1
  •   dfa    16 年前

    是的,Java也使用 floating point 算术。

        9
  •  1
  •   eipipuz    16 年前

    当然是真的。想想看。任何数字都必须用二进制表示。

    图片:“1000”表示0.5或1/2,即2**-1。则“0100”为0.25或1/4。你可以看到我要去哪里。

    你能用这种方式代表多少个数字?2×4。添加更多的位会复制可用空间,但它永远不会是无限的。1/3或1/10,对于1/n,任何不是2的倍数的数字都不能真正表示。

    1/3可以是“0101”(0.3125)或“0110”(0.375)。任何一个值如果乘以3,都不会是1。当然可以添加特殊规则。说你“当你加3次‘0101’,使它1”…从长远来看,这种方法是行不通的。你可以抓到一些,但是1/6乘以2怎么样?

    这不是二进制表示的问题,任何有限表示都有你不能表示的数字,毕竟它们是无限的。