web-dev-qa-db-fra.com

Java: Comparaison de la valeur double

Devons-nous faire attention lorsque nous comparons une valeur double à zéro?

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

Si vous voulez être très prudent, vous pouvez vérifier si elle se situe dans les limites de zéro avec quelque chose comme: 

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

Ou vous pouvez simplement arrondir vos doubles à une précision spécifiée avant de créer des branches. 

Pour des détails intéressants sur la comparaison des erreurs en nombres à virgule flottante, voici un article de Bruce Dawson .

17
Crashworks

Pour l'égalité: (c'est-à-dire == ou !=) oui.

Pour les autres opérateurs comparatifs (<, >, <=, >=), cela dépend de savoir si vous êtes sur les cas Edge, par exemple. si < est équivalent à <=, ce qui est un autre cas d'égalité. Si vous ne vous souciez pas des cas Edge, cela n'a généralement pas d'importance, bien que cela dépend de l'origine et de la manière dont les chiffres que vous entrez sont entrés. 

Si vous vous attendez à ce que (3.0/10.0) <= 0.3 soit évalué en tant que true (il ne le sera pas si une erreur en virgule flottante entraîne l'évaluation de 3.0/10.0 sur un nombre légèrement supérieur à 0.3, par exemple 0.300000000001), et votre programme se comportera mal s'il évalue en tant que false - c'est un bord cas, et vous devez faire attention.

Les bons algorithmes numériques ne devraient presque jamais dépendre d'égalité et de cas Edge. Si j'ai un algorithme qui prend en entrée 'x' qui est un nombre compris entre 0 et 1, en général, peu importe si 0 < x < 1 ou 0 <= x <= 1. Il existe toutefois des exceptions: vous devez faire attention lorsque vous évaluez des fonctions avec des points de branche ou des singularités. 

Si j'ai une quantité intermédiaire y et que j'attends y >= 0, et que j'évalue sqrt(y), je dois être certain que les erreurs en virgule flottante ne font pas de y un nombre négatif très petit et que la fonction sqrt() renvoie une erreur. (En supposant qu'il s'agisse d'une situation dans laquelle les nombres complexes ne sont pas impliqués.) Si je ne suis pas sûr de l'erreur numérique, j'évaluerais probablement sqrt(max(y,0)) à la place. 

Pour des expressions telles que 1/y ou log(y), dans la pratique, peu importe que y soit égal à zéro (auquel cas vous obtenez une erreur de singularité) ou à un nombre très proche de zéro (auquel cas vous obtiendrez un très grand nombre out, dont la magnitude est très sensible à la valeur de y) - les deux cas sont "mauvais" d’un point de vue numérique, et j’ai besoin de réévaluer ce que j’essaie de faire et le comportement que je recherche quand y valeurs sont au voisinage de zéro.

9
Jason S

Selon le mode de calcul de votre someAmount, vous pouvez vous attendre à un comportement étrange avec float/double

Fondamentalement, la conversion de données numériques en leur représentation binaire à l'aide de float/doubles est sujette aux erreurs, car certains nombres ne peuvent pas être représentés avec un exposant/Mantis.

Pour plus de détails à ce sujet, vous pouvez lire ce petit article

Vous devriez envisager d'utiliser Java.lang.Math.signum ou Java.math.BigDecimal, en particulier pour le calcul monétaire et fiscal

6
WiseTechi

Attention au déballage automatique:

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

Boom, NullPointerException.

5
Thilo

Oui tu devrais faire attention.

Suggestion: L’un des bons moyens consiste à utiliser BigDecimal pour vérifier l’égalité/non-égalité à 0:

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

0 != balance.compareTo(BigDecimal.ZERO)

Explication: 

La fonction compareTo() compare cette BigDecimal à la BigDecimal spécifiée. Deux objets BigDecimal qui ont la même valeur mais qui ont une échelle différente (comme 2.0 et 2.00) sont considérés comme égaux par cette méthode. Cette méthode est fournie de préférence aux méthodes individuelles pour chacun des six opérateurs de comparaison boolean(<, ==, >, >=, !=, <=). L'idiome suggéré pour effectuer ces comparaisons est le suivant: (x.compareTo(y) <op> 0), où est l'un des six opérateurs de comparaison.

(Merci à la documentation SonarQube)

Les calculs en virgule flottante sont imprécis en raison du défi que représente le stockage de telles valeurs dans une représentation binaire. Pire encore, les mathématiques en virgule flottante ne sont pas associatives; Poussez un float ou un double à travers une série d'opérations mathématiques simples et la réponse sera différente en fonction de l'ordre de ces opérations en raison de l'arrondi effectué à chaque étape.

Même les assignations en virgule flottante ne sont pas simples:

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

(Les résultats varient en fonction des paramètres du compilateur et du compilateur);

Par conséquent, l'utilisation des opérateurs d'égalité (==) et d'inégalité (! =) Sur des valeurs flottantes ou doubles est presque toujours une erreur. Au lieu de cela, la meilleure solution consiste à éviter les comparaisons en virgule flottante. Lorsque ce n'est pas possible, vous devez envisager d'utiliser l'un des numéros de traitement flottant de Java, tels que BigDecimal, qui permet de gérer correctement les comparaisons à virgule flottante. Une troisième option consiste à rechercher non pas une égalité, mais plutôt à déterminer si la valeur est suffisamment proche. C'est à dire. Comparez la valeur absolue de la différence entre la valeur stockée et la valeur attendue par rapport à une marge d'erreur acceptable. Notez que cela ne couvre pas tous les cas (NaN et Infinity par exemple).

1
VibrantVivek

Si vous ne vous souciez pas des cas Edge, alors testez simplement someAmount <= 0. Cela clarifie l'intention du code. Si vous vous en souciez, eh bien ... cela dépend de la façon dont vous calculez someAmount et de la raison pour laquelle vous testez l'inégalité.

0
quant_dev

Vérifiez qu'une valeur double ou float est 0, un seuil d'erreur est utilisé pour détecter si la valeur est proche de 0, mais pas tout à fait 0. Je pense que cette méthode est la meilleure des choses que j'ai rencontrées.

Comment tester si un double est égal à zéro? Répondu par @ William Morrison

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

Par exemple, définissez le seuil sur 0. comme ceci,

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

Les résultats sont vrais, vrais et faux à partir des exemples de code ci-dessus.

S'amuser @.@

0
Luna Kong