提问人:owns good 提问时间:10/26/2022 更新时间:10/26/2022 访问量:101
浮子型没用?
Float-type useless?
问:
在我的 Java 书中,它告诉我在将 2 个不同的 float(type) 数字存储在变量中时不要直接比较它们。因为它在变量中给出了一个近似的数字。相反,它建议检查差值的绝对值,看看它是否等于 0。如果是这样,它们是相同的。这有什么帮助?如果我将 5 存储在变量 a 中,将 5 存储在变量 b 中,它们怎么可能不相同呢?如果我比较绝对值,它有什么帮助?
double a=5,b=5;
if (Math.abs(a-b)==0)
//run code
if (a==b)
//run code
我完全不明白为什么上述方法会更准确?因为如果“a”不等于“b”,那么我是否使用 Math.abs 也没关系。
感谢您的回复,并感谢您抽出宝贵时间接受采访。
我尝试了这两种方法。
答:
使用 == 运算符进行比较不准确是由双精度值在计算机内存中的存储方式引起的。我们需要记住,有限的内存空间(通常是 64 位)必须容纳无限数量的值。因此,我们无法在计算机中精确表示大多数双精度值。它们必须四舍五入才能保存。
由于舍入不准确,可能会出现有趣的错误:
double d1 = 0;
for (int i = 1; i <= 8; i++) {
d1 += 0.1;
}
double d2 = 0.1 * 8;
System.out.println(d1);
System.out.println(d2);
两个变量 d1 和 d2 都应等于 0.8。但是,当我们运行上面的代码时,我们将看到以下结果:
0.7999999999999999
0.8
在这种情况下,使用 == 运算符比较这两个值将产生错误的结果。因此,我们必须使用更复杂的比较算法。
如果我们想对舍入机制有最好的精度和控制,我们可以使用 java.math.BigDecimal 类。
在纯 Java 中比较双精度值的推荐算法是一种阈值比较方法。在这种情况下,我们需要检查两个数字之间的差值是否在指定的容差范围内,通常称为epsilon:
double epsilon = 0.000001d;
assertThat(Math.abs(d1 - d2) < epsilon).isTrue();
epsilon 的值越小,比较精度越高。但是,如果我们指定的公差值太小,我们将得到与简单 == 比较相同的错误结果
评论
Math.abs(d1 - d2) < epsilon
采取浮出的有用性。当 和 是连续的 ,并且像 1e20 这样大,总是假的。当 和 不接近连续 ,并且像 1e-20 一样小,总是正确的。 应根据所涉及的值的大小进行缩放。double
d1
d2
double
Math.abs(d1 - d2) < epsilon
d1
d2
double
Math.abs(d1 - d2) < epsilon
epsilon
问题是,你在 java 书中读到的那句话只是防止你将来出现一些错误,这些错误很难调试。计算机将小数/浮点数存储为二进制,因此并非所有我们可以用十进制数表示为有理数的东西都可以用二进制表示为有理数,所以总是有类似 0.7 = 0.6999999999998511 的东西。在你使用的那些比较中,你可能不会看到差异,但在实际项目中,你可能会使用更多的变量,从中加减,这种差异可能会出现在非常令人惊讶的地方。
关于浮点数有一些经典的问题。您也可以在任何语言中看到它 为什么此代码打印“7”的结果?
评论
abs
if (Math.abs(a - b) < 0.00001)