Le compactage de nombreux nombres réels infinis en un nombre fini de bits nécessite une représentation approximative. La plupart des programmes stockent le résultat des calculs d'entiers sur 32 ou 64 bits maximum. Étant donné un nombre fixe de bits, la plupart des calculs avec des nombres réels produiront des quantités qui ne peuvent pas être représentées exactement en utilisant autant de bits. Par conséquent, le résultat d’un calcul en virgule flottante doit souvent être arrondi pour rentrer dans sa représentation finie. Cette erreur d’arrondi est une caractéristique du calcul en virgule flottante. Par conséquent, lors de la gestion des calculs avec des nombres à virgule flottante (surtout si les calculs sont en termes d'argent), nous devons prendre en compte les erreurs d'arrondi dans un langage de programmation. Voyons un exemple :
Javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
pivot du serveur SQL
Sortir:
x = 0.7999999999999999
y = 0.8
false
Ici, la réponse n’est pas celle à laquelle nous nous attendions, car l’arrondi est effectué par le compilateur Java.
Raison derrière l’erreur d’arrondi
Les types de données Float et Double implémentent la spécification IEEE 754 à virgule flottante. Cela signifie que les nombres sont représentés sous une forme comme :
SIGN FRACTION * 2 ^ EXP 0,15625 = (0,00101)2qui, au format virgule flottante, est représenté par : 1,01 * 2^-3
Toutes les fractions ne peuvent pas être représentées exactement comme une fraction d’une puissance de deux. À titre d'exemple simple 0,1 = (0,000110011001100110011001100110011001100110011001100110011001… )2 et ne peut donc pas être stocké dans une variable à virgule flottante.
Un autre exemple :
javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
Sortir:
x = 0.7999999999999999
y = 0.8
false
Autre exemple :
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); // Value of a is expected as 0.1 System.out.println('a = ' + a); } }
Sortir:
a = 0.09999999999999998Comment corriger les erreurs d’arrondi ?
- Arrondissez le résultat : La fonction Round() peut être utilisée pour minimiser les effets de l'inexactitude du stockage arithmétique en virgule flottante. L'utilisateur peut arrondir les nombres au nombre de décimales requis par le calcul. Par exemple, lorsque vous travaillez avec des devises, vous arrondirez probablement à 2 décimales.
- Algorithmes et fonctions : Utilisez des algorithmes numériquement stables ou concevez vos propres fonctions pour gérer de tels cas. Vous pouvez tronquer/arrondir les chiffres dont vous n'êtes pas sûr qu'ils soient corrects (vous pouvez également calculer la précision numérique des opérations)
- Classe BigDecimal : Vous pouvez utiliser le java.math.BigDecimal classe conçue pour nous donner de la précision, en particulier dans le cas de grands nombres fractionnaires. Le programme suivant montre comment l'erreur peut être supprimée :
import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String args[]) { BigDecimal a = new BigDecimal('1.0'); BigDecimal b = new BigDecimal('0.10'); BigDecimal x = b.multiply(new BigDecimal('9')); a = a.subtract(x); // Rounding to 1 decimal place a = a.setScale(1 RoundingMode.HALF_UP); System.out.println('a = ' + a); } }
Sortir:
0.1Ici a = a.setScale(1 RoundingMode.HALF_UP);
Tours aà 1 décimale en utilisant le mode d'arrondi HALF_UP. Ainsi, l'utilisation de BigDecimal offre un contrôle plus précis sur les opérations arithmétiques et d'arrondi, ce qui peut être particulièrement utile pour les calculs financiers ou d'autres cas où la précision est cruciale.
Remarque importante :
Math.round arrondit la valeur à l'entier le plus proche. Comme 0,10 est plus proche de 0 que de 1, il est arrondi à 0. Après arrondi et division par 1,0, le résultat est 0,0. Vous pouvez donc remarquer la différence entre les sorties avec la classe BigDecimal et la fonction Maths.round.
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); /* We use Math.round() function to round the answer to closest long then we multiply and divide by 1.0 to to set the decimal places to 1 place (this can be done according to the requirements.*/ System.out.println('a = ' + Math.round(a*1.0)/1.0); } }
Sortir:
0.0