在我的课程中,有人告诉我:
连续值在内存中近似表示,因此使用浮点数进行计算涉及舍入误差。这些是位模式的微小差异;因此,如果和是浮动的,测试
e==f
是不安全的。e
f
参考Java。
这是真的?我使用double
s 和float
s 的比较语句并且从未遇到过舍入问题。我从来没有在教科书中读过类似的东西。虚拟机肯定会解决这个问题吗?
在我的课程中,有人告诉我:
连续值在内存中近似表示,因此使用浮点数进行计算涉及舍入误差。这些是位模式的微小差异;因此,如果和是浮动的,测试
e==f
是不安全的。e
f
参考Java。
这是真的?我使用double
s 和float
s 的比较语句并且从未遇到过舍入问题。我从来没有在教科书中读过类似的东西。虚拟机肯定会解决这个问题吗?
是真的。
这是浮点值如何在内存中以有限位数表示的固有限制。
例如,这个程序打印“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);
是的,以 2 为底数精确表示 0.1 与试图以 10 为底数精确表示 1/3 相同。
这总是正确的。有些数字无法使用浮点表示准确表示。例如,考虑 pi。您将如何在有限的存储空间中表示具有无限位的数字?因此,在比较数字时,您应该检查它们之间的差异是否小于某个 epsilon。此外,还有几个类可以帮助您获得更高的准确性,例如 BigDecimal 和 BigInteger。
这是正确的。请注意,Java 与它无关,这个问题是任何语言的浮点数学所固有的。
您通常可以解决课堂级别的问题,但它在现实世界中行不通。有时它在课堂上是行不通的。
很久以前在学校发生的一件事。入门课的老师布置了一道期末考试题,这对许多成绩较好的学生来说确实很棘手——它不起作用,他们也不知道为什么。(我作为实验室助理看到了这个,我不在课堂上。)最后一些人开始向我寻求帮助,一些探索揭示了问题:他们从未被教导过浮点数学固有的不准确性。
现在,有两种基本方法来解决这个问题,一种是蛮力方法(在这种情况下偶然会起作用,因为它每次都会犯相同的错误)和一种更优雅的方法(它会犯不同的错误并且不起作用)。尝试了优雅的方法会撞到砖墙,却不知道为什么。我帮助了他们中的许多人,并坚持发表评论解释原因,如果他有问题,请与我联系。
当然,下学期我从他那里听说了这件事,我基本上用一个简单的小程序让整个系都大吃一惊:
10 X = 3000000
20 X = X + 1
30 If X < X + 1 goto 20
40 Print "X = X + 1"
不管系里的每一位老师都怎么想,这将终止。300万种子只是为了让它更快终止。(如果你不懂基本:这里没有噱头,只是耗尽了浮点数的精度。)
是的,正如其他答案所说。我想补充一点,我向您推荐这篇关于浮点精度的文章:Visualizing floats
当然这是真的。想想看。任何数字都必须以二进制表示。
图片:“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 怎么样?
这不是二进制表示的问题,任何有限表示都有你无法表示的数字,它们毕竟是无限的。
大多数 CPU(和计算机语言)使用 IEEE 754 浮点运算。使用这种表示法,有一些十进制数在这种表示法中没有精确的表示,例如 0.1。因此,如果您将 1 除以 10,您将不会得到准确的结果。当连续执行多个计算时,错误会相加。在 python 中尝试以下示例:
>>> 0.1
0.10000000000000001
>>> 0.1 / 7 * 10 * 7 == 1
False
这并不是你在数学上所期望的。
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.
是的,Java 也使用浮点运算。