在将双值与零比较时,我们需要小心吗?
if ( someAmount <= 0){
.....
}
答案 0 :(得分:18)
如果你想要非常小心,你可以用
之类的东西来测试它是否在零的epsilon中double epsilon = 0.0000001;
if ( f <= ( 0 - epsilon ) ) { .. }
else if ( f >= ( 0 + epsilon ) ) { .. }
else { /* f "equals" zero */ }
或者您可以在分支之前简单地将双打舍入到指定的精度。
有关比较浮点数中的错误的一些有趣详细信息here is an article by Bruce Dawson。
答案 1 :(得分:9)
对于平等:(即==
或!=
)是。
对于其他比较运营商(<
,>
,<=
,>=
),这取决于您是否与边缘情况有关,例如<
是否等同于<=
,这是另一种平等的情况。如果你不关心边缘情况,它通常无关紧要,尽管它取决于输入数字的来源以及它们的使用方式。
如果您期望(3.0/10.0) <= 0.3
评估为true
(如果浮点错误导致3.0 / 10.0评估为略大于0.3的数字,如0.300000000001,则可能不会),并且您的程序将表现出来如果它评估为false
那么严重 - 这是一个边缘情况,你需要小心。
好的数值算法几乎不应该依赖于相等和边缘情况。如果我有一个算法,它将输入“x
”作为0到1之间的任意数字,通常无论0 < x < 1
还是0 <= x <= 1
都无关紧要。但也有例外:在评估具有分支点或奇点的函数时必须小心。
如果我有一个中间数量y
并且我期待y >= 0
,并且我评估sqrt(y)
,那么我必须确定浮点错误不会导致y成为一个非常小的负数和sqrt()
函数抛出错误。 (假设这是一个不涉及复数的情况。)如果我不确定数字错误,我可能会评估sqrt(max(y,0))
。
对于像1/y
或log(y)
这样的表达式,在实际意义上,y是否为零(在这种情况下,您得到奇点误差)或y是非常接近零的数字并不重要(在这种情况下,你会得到一个非常大的数字,其数量对y的值非常敏感 - 从数字的角度来看,这两种情况都是“坏的”,我需要重新评估我正在尝试的是什么当y
值在零附近时,我正在寻找什么行为。
答案 2 :(得分:6)
根据你的someAmount
的计算方式,你可能会发现浮动/双打的奇怪行为
基本上,使用float / double将数值数据转换为二进制表示是容易出错的,因为有些数字不能用螳螂/指数表示。
有关此问题的一些详情,请阅读this small article
您应该考虑使用java.lang.Math.signum
或java.math.BigDecimal
,尤其是货币和货币。税收计算
答案 3 :(得分:5)
注意自动拆箱:
Double someAmount = null;
if ( someAmount <= 0){
Boom,NullPointerException。
答案 4 :(得分:1)
是的,你应该小心。
建议:使用BigDecimal
检查相等/不相等为0的好方法之一是:
BigDecimal balance = pojo.getBalance();//get your BigDecimal obj
0 != balance.compareTo(BigDecimal.ZERO)
说明:
compareTo()
函数将此BigDecimal
与指定的BigDecimal
进行比较。通过此方法,两个BigDecimal
个值相等但具有不同比例(如2.0和2.00)的对象被认为是相等的。优先于六个boolean
比较运算符(<, ==, >, >=, !=, <=)
中的每一个的单独方法提供此方法。执行这些比较的建议惯用法是:(x.compareTo(y) <op> 0)
,其中六个比较运算符之一。
(感谢SonarQube文档)
由于在二进制表示中存储这些值的挑战,浮点数学是不精确的。更糟糕的是,浮点数学不是关联的;通过一系列简单的数学运算推动浮点数或双精度数,由于每一步的舍入,答案将根据这些操作的顺序而有所不同。
即使是简单的浮点分配也不简单:
float f = 0.1; // 0.100000001490116119384765625
double d = 0.1; // 0.1000000000000000055511151231257827021181583404541015625
(结果将根据编译器和编译器设置而有所不同);
因此,在float或double值上使用等于(==)和不等(!=)运算符几乎总是一个错误。相反,最好的方法是完全避免浮点比较。如果无法做到这一点,您应该考虑使用Java的浮点处理数字之一,例如BigDecimal,它可以正确处理浮点比较。第三种选择是不要考虑相等性,而是考虑价值是否足够接近。即比较存储值和期望值之间的差值的绝对值与可接受误差的余量。请注意,这并未涵盖所有情况(例如NaN和Infinity)。
答案 5 :(得分:0)
如果您不关心边缘情况,那么只需测试someAmount <= 0
。它使代码的意图清晰。如果你关心,那么......这取决于你如何计算someAmount
以及为什么要测试不平等。
答案 6 :(得分:0)
检查double或float值是否为0,错误阈值用于检测值是否接近0,但不是0.我认为这种方法是我遇到的最好的方法。
How to test if a double is zero? 回答@William Morrison
public boolean isZero(double value, double threshold){
return value >= -threshold && value <= threshold;
}
例如,将阈值设置为0.像这样,
System.out.println(isZero(0.00, 0));
System.out.println(isZero(0, 0));
System.out.println(isZero(0.00001, 0));
以上示例代码中的结果为true,true和false。
玩得开心@。@