舍入错误?

时间:2009-06-06 16:41:56

标签: java memory floating-accuracy

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

  

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

参考Java。

这是真的吗?我使用了doublefloat的比较语句,并且从未遇到过舍入问题。从来没有我在课本上读过类似的东西。当然虚拟机可以解决这个问题吗?

9 个答案:

答案 0 :(得分:50)

确实如此。

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

例如,该程序打印“false”:

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);

答案 1 :(得分:25)

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

有关浮点值的更多信息:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

答案 2 :(得分:8)

是的,在base-2中完全代表0.1与尝试在基数10中完全代表1/3相同。

答案 3 :(得分:4)

这总是如此。有些数字无法使用浮点表示法准确表示。例如,考虑pi。在有限的存储空间中,您如何表示具有无限数字的数字?因此,在比较数字时,您应该检查它们之间的差异是否小于某个epsilon。此外,还有几个类可以帮助您实现更高的准确性,例如BigDecimal和BigInteger。

答案 4 :(得分:4)

是对的。请注意,Java与它无关,这个问题是 ANY 语言中浮点数学所固有的。

你经常可以通过课堂级别的问题来解决它,但它不会在现实世界中发挥作用。有时它在课堂上不起作用。

很久以前回到学校的事件。一个介绍班的老师分配了一个期末考试问题,这对许多优秀的学生来说是一个真正的困难 - 它不起作用,他们不知道为什么。 (我看到这是一个实验室助理,我不在课堂上。)最后有些人开始向我寻求帮助,一些探测揭示了这个问题:他们从来没有被教过浮点数学固有的不准确性。

现在,这个问题有两种基本的方法,一种是暴力的方法(在这种情况下偶然起作用,因为它每次都产生相同的错误)和一种更优雅的方法(这会产生不同的错误,而不是工作。任何尝试过优雅方法的人都会碰到砖墙而不知道为什么。我帮助他们中的一大堆并发表评论,解释原因并在他有疑问时与我联系。

当然下学期我听到他的消息,我基本上用一个简单的小程序来解决整个部门:

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

尽管该部门的每位老师都认为,这个终止。 300万种子只是为了让它更快地终止。 (如果你不知道基本:这里没有噱头,只是用尽了浮点数的精度。)

答案 5 :(得分:2)

是的,正如其他答案所说。我想补充一点,我建议你这篇关于浮点精度的文章:Visualizing floats

答案 6 :(得分:2)

大多数CPU(和计算机语言)使用IEEE 754浮点运算。使用这种表示法,有十进制数字在这种表示法中没有精确的表示,例如0.1。因此,如果将1除以10,则无法得到确切的结果。连续执行多次计算时,错误总结。在python中尝试以下示例:

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

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

顺便说一下: 关于浮点数的常见误解是,结果不精确且不能安全地共同映射。只有在真正使用数字分数时才会出现这种情况。如果所有数学都在整数域中,则double和float与int完全相同,也可以安全地进行比较。例如,它们可以安全地用作循环计数器。

答案 7 :(得分:1)

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

答案 8 :(得分:1)

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

图片:“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?

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

相关问题