Java:双值比较

时间:2009-01-12 06:59:33

标签: java double

在将双值与零比较时,我们需要小心吗?

if ( someAmount <= 0){
.....
}

7 个答案:

答案 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/ylog(y)这样的表达式,在实际意义上,y是否为零(在这种情况下,您得到奇点误差)或y是非常接近零的数字并不重要(在这种情况下,你会得到一个非常大的数字,其数量对y的值非常敏感 - 从数字的角度来看,这两种情况都是“坏的”,我需要重新评估我正在尝试的是什么当y值在零附近时,我正在寻找什么行为。

答案 2 :(得分:6)

根据你的someAmount的计算方式,你可能会发现浮动/双打的奇怪行为

基本上,使用float / double将数值数据转换为二进制表示是容易出错的,因为有些数字不能用螳螂/指数表示。

有关此问题的一些详情,请阅读this small article

您应该考虑使用java.lang.Math.signumjava.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。

玩得开心@。@