Java 舍入错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/960072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:35:27  来源:igfitidea点击:

Rounding Errors?

javamemoryfloating-accuracy

提问by Humphrey Bogart

In my course, I am told:

在我的课程中,有人告诉我:

Continuous values are represented approximately in memory, and therefore computing with floats involves rounding errors. These are tiny discrepancies in bit patterns; thus the test e==fis unsafe if eand fare floats.

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

Referring to Java.

参考Java。

Is this true? I've used comparison statements with doubles and floats and have never had rounding issues. Never have I read in a textbook something similar. Surely the virtual machine accounts for this?

这是真的?我使用了带有doubles 和floats 的比较语句,并且从未遇到过舍入问题。我从来没有在教科书中读过类似的东西。虚拟机肯定是这个原因吗?

采纳答案by Chris Vest

It is true.

是真的。

It is an inherent limitation of how floating point values are represented in memory in a finite number of bits.

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

This program, for instance, prints "false":

例如,这个程序打印“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);
  }
}

Instead of exact comparison with '==' you usually decide on some level of precision and ask if the numbers are "close enough":

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

System.out.println(Math.abs(x - y) < 0.0001);

回答by laginimaineb

This is always true. There are some numbers which cannot be represented accurately using float point representation. Consider, for example, pi. How would you represent a number which has infinite digits, within a finite storage? Therefore, when comparing numbers you should check if the difference between them is smaller then some epsilon. Also, there are several classes which exist that can help you achieve greater accuracy such as BigDecimal and BigInteger.

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

回答by dfa

yes, Java also uses floating pointarithmetic.

是的,Java 也使用浮点运算。

回答by Ben Schwehn

This applies to Java just as much as to any other language using floating point. It's inherent in the design of the representation of floating point values in hardware.

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

More info on floating point values:

有关浮点值的更多信息:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

每个计算机科学家都应该了解的关于浮点运算的知识

回答by Artur Soler

Yes, as other answers have said. I want to add that I recommend you this article about floating point accuracy: Visualizing floats

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

回答by duffymo

Yes, representing 0.1 exactly in base-2 is the same as trying to represent 1/3 exactly in base 10.

是的,以 2 为底精确表示 0.1 与试图以 10 为基精确表示 1/3 相同。

回答by Loren Pechtel

It is right. Note that Java has nothing to do with it, the problem is inherent in floating point math in ANYlanguage.

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

You can often get away with it with classroom-level problems but it's not going to work in the real world. Sometimes it won't work in the classroom.

您通常可以解决课堂级问题,但在现实世界中却行不通。有时它在课堂上不起作用。

An incident from long ago back in school. The teacher of an intro class assigned a final exam problem that was proving a real doozy for many of the better students--it wasn't working and they didn't know why. (I saw this as a lab assistant, I wasn't in the class.) Finally some started asking me for help and some probing revealed the problem: They had never been taught about the inherent inaccuracy of floating point math.

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

Now, there were two basic approaches to this problem, a brute force one (which by chance worked in this case as it made the same errors every time) and a more elegant one (which would make different errors and not work.) Anyone who tried the elegant approach would hit a brick wall without having any idea why. I helped a bunch of them and stuck in a comment explaining why and to contact me if he had questions.

现在,有两种基本方法可以解决这个问题,一种是蛮力方法(在这种情况下偶然会起作用,因为它每次都会犯相同的错误)和一种更优雅的方法(会犯不同的错误并且不起作用)。尝试优雅的方法会撞到砖墙而不知道为什么。我帮助了他们中的很多人,并在评论中解释了原因,并在他有问题时与我联系。

Of course next semester I hear from him about this and I basically floored the entire department with a simple little program:

当然,下学期我从他那里听到了这件事,我基本上用一个简单的小程序让整个部门都满意:

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

Despite what every teacher in the department thought, this WILLterminate. The 3 million seed is simply to make it terminate faster. (If you don't know basic: There are no gimmicks here, just exhausting the precision of floating point numbers.)

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

回答by eipipuz

Of course it is true. Think about it. Any number must be represented in binary.

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

Picture: "1000" as 0.5or 1/2, that is, 2 ** -1. Then "0100" is 0.25 or 1/4. You can see where I'm going.

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

How many numbers can you represent in this manner? 2**4. Adding more bits duplicates the available space, but it is never infinite. 1/3 or 1/10, for the matter 1/n, any number not multiple of 2 cannot be really represented.

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

1/3 could be "0101" (0.3125) or "0110" (0.375). Either value if you multiply it by 3, will not be 1. Of course you could add special rules. Say you "when you add 3 times '0101', make it 1"... this approach won't work in the long run. You can catch some but then how about 1/6 times 2?

1/3 可以是“0101”(0.3125)或“0110”(0.375)。如果将其乘以 3,则任一值都不会是 1。当然您可以添加特殊规则。假设您“当您添加 3 次 '0101' 时,将其设为 1”……这种方法从长远来看是行不通的。你可以抓到一些,但是 1/6 乘以 2 怎么样?

It's not a problem of binary representation, any finite representation has numbers that you cannot represent, they are infinite after all.

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

回答by Nikolai Ruhe

Most CPUs (and computer languages) use IEEE 754 floating point arithmetic. Using this notation, there are decimal numbers that have no exact representation in this notation, e.g. 0.1. So if you divide 1 by 10 you won't get an exact result. When performing several calculations in a row, the errors sum up. Try the following example in python:

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

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

That's not really what you'd expect mathematically.

这不是您在数学上真正期望的。

By the way: A common misunderstanding concerning floating point numbers is, that the results are not precise and cannot be comapared safely. This is only true if you really use fractions of numbers. If all your math is in the integer domain, doubles and floats do exactly the same as ints and also can be compared safely. They can be safely used as loop counters, for example.

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