检查双打是否存在平等和声纳问题

时间:2015-06-19 15:34:20

标签: java double sonarqube equality

我们正在使用Sonar检查代码的质量,而Sonar找到的代码将float或double的相等性与常量值进行比较,如下所示:

if (x == 0.0) { … }

变量与(0.0)比较的值是常量,如果变量可以等于此值,则该值也不会计算,只能通过常量设置。这通常用于检查变量是否尚未设置或仍处于初始化状态,例如: G。在值只能为正值的情况下,-1.0可能会用于“尚未设置”。

因此,由于这些值永远不会计算,而只是从常量设置,因此Sonar投诉对我们没用。仅对于计算值(或者不能精确表示为浮点数或双精度值的断裂值),关于平等测试的投诉才有意义。

我现在的问题是:更改代码的最佳做法是什么,以便Sonar不再抱怨这个?

我看到了几个选项:

  1. 将“test-for-unset”解压缩为特殊测试功能;但这只会减少发生次数(减少到1),而不是一般的问题。
  2. 将Sonar的代码标记为使用特殊的装饰器忽略它。但我们希望避免使用这些装饰器。
  3. 隐藏比较背后的比较,例如(0.0 <= x && x <= 0.0)!(x != 0.0)(目前似乎对Sonar没问题。)
  4. 调用Double.doubleToRawLongBits()比较值的位,如下所示:(Double.doubleToRawLongBits(x) != Double.doubleToRawLongBits(0.0))
  5. 其他想法?
  6. 我真的不喜欢这些解决方案,我想,也许,有一个我想不到的更好的解决方案。

7 个答案:

答案 0 :(得分:16)

我会选择你的第二个选择:

  

将Sonar的代码标记为使用特殊装饰器忽略它。

不要成为静态代码分析工具的奴隶。他们并不完美,告诉他们闭嘴没什么不对。我在使用@SuppressLint等注释时的个人做法是包含一条解释我正在使用注释的注释。

那就是说,我会创建一个常量,所以代码更加不言自明:

private static final double UNINITIALIZED = 0.0;
if (x == UNINITIALIZED) { … }

答案 1 :(得分:4)

这里最好的选择是将问题标记为误报并发表评论。这样,问题和相关的技术债务将从您的SonarQube实例中消失,而不会使用注释污染您的代码。

答案 2 :(得分:2)

如果您仅对未初始化的值使用这些常量和比较,则可以选择将字段设置为Double.NaN并使用Double.isNaN()进行比较。 E.g:

double notYetInitialized = Double.NaN;
if (Double.isNaN(notYetInitialized)) {
        // handle uninitialized value
}

这使得(某些)读取代码时有意义 - 未初始化的值可能被称为“不是数字”。我无法想象声纳会遇到问题。

答案 3 :(得分:1)

还有正确的方法:

private static final double EPSILON = 0.000000000000001;
if (Math.abs(x) < EPSILON) {

}

答案 4 :(得分:1)

我知道这是一篇非常老的文章,但是我遇到了同样的问题,并使用Equals方法代替了“ ==”运算符。

if (x.Equals(0.0)) { … }

通过这种方式,SonarQube不会抱怨。

再见。

答案 5 :(得分:0)

  

建议:   一种好方法是使用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)。

答案 6 :(得分:-1)

如何转换为(int)? 这应该与您想要检查它是否为零的结果相同。

如果您有计算:

double a = c - b 
boolean x = (int)(a*100) == 0