Java:双值比较

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/434657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:33:10  来源:igfitidea点击:

Java: Double Value Comparison

javadouble

提问by

Do we need to be careful when comparing a double value against zero?

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

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

回答by WiseTechi

Depending on how your someAmountis computed, you may expect some odd behaviour with float/doubles

根据您someAmount的计算方式,您可能会期望浮点数/双精度数出现一些奇怪的行为

Basically, converting numeric data to their binary representation using float / doubles is error prone, because some numbers cannot be represented with a mantis/exponent.

基本上,使用浮点数/双精度数将数字数据转换为二进制表示很容易出错,因为有些数字不能用螳螂/指数表示。

For some details about this you can read this small article

有关这方面的一些详细信息,您可以阅读这篇小文章

You should consider using java.lang.Math.signumor java.math.BigDecimal, especially for currency & tax computing

您应该考虑使用java.lang.Math.signumor java.math.BigDecimal,特别是用于货币和税收计算

回答by Crashworks

If you want to be really careful you can test whether it is within some epsilon of zero with something like

如果你想非常小心,你可以用类似的东西测试它是否在零的某个 epsilon 之内

double epsilon = 0.0000001;
if      ( f <= ( 0 - epsilon ) ) { .. }
else if ( f >= ( 0 + epsilon ) ) { .. }
else { /* f "equals" zero */ }

Or you can simply round your doubles to some specified precision before branching on them.

或者,您可以简单地将双精度舍入到某个指定的精度,然后再对其进行分支。

For some interesting details about comparing error in floating point numbers, here is an article by Bruce Dawson.

有关比较浮点数误差的一些有趣细节,请参阅Bruce Dawson 的文章

回答by Thilo

Watch out for auto-unboxing:

注意自动拆箱:

Double someAmount = null;
if ( someAmount <= 0){

Boom, NullPointerException.

繁荣,空指针异常。

回答by Jason S

For equality: (i.e. ==or !=) yes.

对于平等:(即==!=)是。

For the other comparative operators (<, >, <=, >=), it depends whether you are about the edge cases, e.g. whether <is equivalent to <=, which is another case of equality. If you don't care about the edge cases, it usually doesn't matter, though it depends where your input numbers come from and how they are used.

对于其他比较运算符(<, >, <=, >=),这取决于您是否关注边缘情况,例如是否<等于<=,这是另一种相等的情况。如果您不关心边缘情况,则通常无关紧要,尽管这取决于您输入的数字来自何处以及如何使用它们。

If you are expecting (3.0/10.0) <= 0.3to evaluate as true(it may not if floating point error causes 3.0/10.0 to evaluate to a number slightly greater than 0.3 like 0.300000000001), and your program will behave badly if it evaluates as false-- that's an edge case, and you need to be careful.

如果您希望(3.0/10.0) <= 0.3评估为true(如果浮点错误导致 3.0/10.0 评估为略大于 0.3 的数字,例如 0.300000000001,则可能不会),并且您的程序将表现不佳如果它评估为false- 这是一个边缘情况,并且你需要小心。

Good numerical algorithms should almost never depend on equality and edge cases. If I have an algorithm which takes as an input 'x' which is any number between 0 and 1, in general it shouldn't matter whether 0 < x < 1or 0 <= x <= 1. There are exceptions, though: you have to be careful when evaluating functions with branch points or singularities.

好的数值算法几乎不应该依赖于平等和边缘情况。如果我有一个将 ' x'作为输入的算法,它是 0 到 1 之间的任何数字,一般来说,无论是0 < x < 1还是0 <= x <= 1. 但也有例外:在评估具有分支点或奇点的函数时必须小心。

If I have an intermediate quantity yand I am expecting y >= 0, and I evaluate sqrt(y), then I have to be certain that floating-point errors do not cause y to be a very small negative number and the sqrt()function to throw an error. (Assuming this is a situation where complex numbers are not involved.) If I'm not sure about the numerical error, I would probably evaluate sqrt(max(y,0))instead.

如果我有一个中间量y并且我期望y >= 0,并且我评估sqrt(y),那么我必须确定浮点错误不会导致 y 成为非常小的负数并且sqrt()函数会引发错误。(假设这是不涉及复数的情况。)如果我不确定数值错误,我可能会进行评估sqrt(max(y,0))

For expressions like 1/yor log(y), in a practical sense it doesn't matter whether y is zero (in which case you get a singularity error) or y is a number very near zero (in which case you'll get a very large number out, whose magnitude is very sensitive to the value of y) -- both cases are "bad" from a numerical standpoint, and I need to reevaluate what it is I'm trying to do, and what behavior I'm looking for when yvalues are in the neighborhood of zero.

对于像1/yor 的表达式log(y),在实际意义上,y 是否为零(在这种情况下您会得到奇点错误)或 y 是非常接近零的数字(在这种情况下您会得到一个非常大的数字)并不重要,其大小对 y 的值非常敏感)——从数字的角度来看,这两种情况都是“坏的”,我需要重新评估我正在尝试做什么,以及当y值是什么时我正在寻找什么行为在零附近。

回答by quant_dev

If you don't care about the edge cases, then just test for someAmount <= 0. It makes the intent of the code clear. If you do care, well... it depends on how you calculate someAmountand why you're testing for the inequality.

如果您不关心边缘情况,那么只需测试someAmount <= 0. 它使代码的意图清晰。如果你真的在意,嗯……这取决于你如何计算someAmount以及你为什么要测试不等式。

回答by Luna Kong

Check a double or float value is 0, an error threshold is used to detect if the value is near 0, but not quite 0. I think this method is the best what I met.

检查 double 或 float 值是否为 0,错误阈值用于检测值是否接近 0,但不完全为 0。我认为这种方法是我遇到的最好的方法。

How to test if a double is zero?Answered by @William Morrison

如何测试双精度值是否为零?由@William Morrison 回答

public boolean isZero(double value, double threshold){
  return value >= -threshold && value <= threshold;
}

For example, set threshold as 0. like this,

例如,将阈值设置为 0。像这样,

System.out.println(isZero(0.00, 0));
System.out.println(isZero(0, 0));
System.out.println(isZero(0.00001, 0));

The results as true, true and false from above example codes.

上述示例代码的结果为真、真和假。

Have Fun @.@

玩得开心 @。@

回答by Vivek

Yes you should be careful.

是的,你应该小心。

Suggestion : One of the good way would be using BigDecimalfor checking equality/non-equality to 0:

建议:一种好方法是BigDecimal用于检查相等/不相等为 0:

BigDecimal balance = pojo.getBalance();//get your BigDecimal obj

0 != balance.compareTo(BigDecimal.ZERO)

Explanation :

解释 :

The compareTo()function compares this BigDecimalwith the specified BigDecimal. Two BigDecimalobjects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. This method is provided in preference to individual methods for each of the six booleancomparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0), where is one of the six comparison operators.

compareTo()函数将其BigDecimal与指定的进行比较BigDecimalBigDecimal值相等但具有不同比例(如 2.0 和 2.00)的两个对象被此方法视为相等。对于六个boolean比较运算符中的每一个,此方法优先于单独的方法提供(<, ==, >, >=, !=, <=)。执行这些比较的建议惯用语是:(x.compareTo(y) <op> 0), where 是六个比较运算符之一。

(Thanks to SonarQube documentation)

(感谢 SonarQube 文档)

Floating point math is imprecise because of the challenges of storing such values in a binary representation. Even worse, floating point math is not associative; push a float or a double through a series of simple mathematical operations and the answer will be different based on the order of those operation because of the rounding that takes place at each step.

由于以二进制表示形式存储这些值的挑战,浮点数学是不精确的。更糟糕的是,浮点数学不是结合的。通过一系列简单的数学运算推动浮点数或双精度数,由于在每一步发生的舍入,答案将根据这些运算的顺序而有所不同。

Even simple floating point assignments are not simple:

即使是简单的浮点赋值也不简单:

float f = 0.1; // 0.100000001490116119384765625
double d = 0.1; // 0.1000000000000000055511151231257827021181583404541015625

(Results will vary based on compiler and compiler settings);

(结果会因编译器和编译器设置而异);

Therefore, the use of the equality (==) and inequality (!=) operators on float or double values is almost always an error. Instead the best course is to avoid floating point comparisons altogether. When that is not possible, you should consider using one of Java's float-handling Numbers such as BigDecimal which can properly handle floating point comparisons. A third option is to look not for equality but for whether the value is close enough. I.e. compare the absolute value of the difference between the stored value and the expected value against a margin of acceptable error. Note that this does not cover all cases (NaN and Infinity for instance).

因此,在 float 或 double 值上使用等号 (==) 和不等号 (!=) 运算符几乎总是错误的。相反,最好的方法是完全避免浮点比较。如果这是不可能的,您应该考虑使用 Java 的浮点处理数字之一,例如 BigDecimal,它可以正确处理浮点比较。第三种选择不是寻找相等性,而是寻找值是否足够接近。即,将存储值和预期值之间的差值的绝对值与可接受的误差范围进行比较。请注意,这并不涵盖所有情况(例如 NaN 和 Infinity)。