CodeGym /Blog Java /Random-FR /BigDecimal en Java
Auteur
Oleksandr Miadelets
Head of Developers Team at CodeGym

BigDecimal en Java

Publié dans le groupe Random-FR
Salut! Dans la leçon d'aujourd'hui, nous allons parler de grands nombres. Non, je veux dire VRAIMENT GROS. Nous avons déjà rencontré à plusieurs reprises le tableau des plages de valeurs pour les types de données primitifs. Il ressemble à ceci:
Type primitif Taille en mémoire Plage de valeurs
octet 8 bits -128 à 127
court 16 bits -32768 à 32767
carboniser 16 bits 0 à 65536
entier 32 bits -2147483648 à 2147483647
long 64 bits -9223372036854775808 à 9223372036854775807
flotter 32 bits (2 puissance -149) à ((2 puissance -23) * 2 puissance 127)
double 64 bits (-2 puissance 63) à ((2 puissance 63) - 1)
booléen 8 (lorsqu'il est utilisé dans des tableaux), 32 (lorsqu'il n'est pas utilisé dans des tableaux) vrai ou faux
Le type de données entier le plus spacieux est le long . En ce qui concerne les nombres à virgule flottante, c'est le double. Mais que se passe-t-il si le nombre dont nous avons besoin est si grand qu'il ne rentre même pas dans un long ? Le type de données Long a une gamme assez large de valeurs possibles, mais il est toujours limité à 64 bits. Que devons-nous trouver si notre Very Large Number nécessite 100 bits? Heureusement, nous n'avons rien à inventer. Pour des cas comme celui-ci, Java a deux classes spéciales : BigInteger (pour les entiers) et BigDecimal(pour les nombres à virgule flottante). Qu'est-ce qui les rend spéciaux? Tout d'abord, en théorie, ils n'ont pas de taille maximale. Nous disons "en théorie", car il n'y a pas d'ordinateurs avec une mémoire infinie. Et si votre programme crée un nombre supérieur à la quantité de mémoire disponible, le programme ne fonctionnera pas, bien sûr. Mais de tels cas sont peu probables. En conséquence, nous pouvons dire que BigInteger et BigDecimal peuvent représenter des nombres de taille pratiquement illimitée. A quoi servent ces cours? Tout d'abord, pour des calculs aux exigences de précision extrêmement rigoureuses. Par exemple, la vie humaine peut dépendre de la précision des calculs dans certains programmes (par exemple, un logiciel qui contrôle des avions, des fusées ou des équipements médicaux). Donc, si la 150ème décimale est importante, alors BigDecimalest le meilleur choix. De plus, les objets de cette classe sont souvent utilisés dans le monde de la finance, où le calcul précis des valeurs, même les plus petites, est également extrêmement important. Comment travaillez-vous avec les objets BigInteger et BigDecimal et avez-vous besoin de les connaître ? Les objets de ces classes sont créés comme ceci :

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Passer une chaîne au constructeur n'est qu'une option possible. Ici, nous utilisons des chaînes, car nos nombres dépassent les valeurs maximales pour long et double , et nous avons besoin d'un moyen d'expliquer au compilateur quel nombre nous voulons créer :) En passant simplement le nombre 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 au constructeur ne fonctionnera pas : Java essaiera d'entasser le nombre passé dans l'un des types de données primitifs, mais il ne rentrera dans aucun d'entre eux. C'est pourquoi l'utilisation d'une chaîne pour transmettre le nombre souhaité est une bonne option. Les deux classes peuvent automatiquement extraire des valeurs numériques des chaînes transmises. Un autre point important à retenir lorsque vous travaillez avec des classes à grand nombre est que leurs objets sont immuables ( Immutable ). Vous êtes déjà familiarisé avec l'immuabilité grâce à votre expérience avec la classe String et les classes wrapper pour les types primitifs (Integer, Long, etc.).

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Sortie console:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Comme vous vous en doutez, notre nombre n'a pas changé. Pour effectuer l'opération d'addition, vous devez créer un nouvel objet pour recevoir le résultat de l'opération.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Sortie console:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Vous voyez, maintenant tout fonctionne comme il se doit :) Au fait, avez-vous remarqué à quel point l'opération d'ajout semble inhabituelle ?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
C'est un autre point important. Les classes à grand nombre n'utilisent pas les opérateurs + - * / . Au lieu de cela, ils fournissent un ensemble de méthodes. Faisons connaissance avec les principales (comme toujours, vous pouvez trouver une liste complète des méthodes dans la documentation d'Oracle : ici et ici ).
  1. méthodes pour les opérations arithmétiques : ajouter() , soustraire() , multiplier() , diviser() . Ces méthodes sont utilisées pour effectuer respectivement l'addition, la soustraction, la multiplication et la division.

  2. doubleValue() , intValue() , floatValue() , longValue() , etc. sont utilisés pour convertir un grand nombre en l'un des types primitifs de Java. Soyez prudent lorsque vous utilisez ces méthodes. N'oubliez pas les différences de taille de bit!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    Sortie console :

    
    8198552921648689607
    
  3. min() et max() vous permettent de trouver la valeur minimale et maximale de deux grands nombres.
    Notez que ces méthodes ne sont pas statiques !

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    Sortie console :

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

Comportement d'arrondi BigDecimal

Cette rubrique a sa propre section distincte, car l'arrondi des grands nombres et la configuration du comportement d'arrondi ne sont pas si simples. Vous pouvez utiliser la méthode setScale() pour définir le nombre de décimales pour un BigDecimal. Par exemple, supposons que nous voulions que le nombre 111,5555555555 ait trois chiffres après la virgule. Cependant, nous ne pouvons pas obtenir ce que nous voulons en passant le nombre 3 comme argument à la méthode setScale() . Comme mentionné ci-dessus, BigDecimalsert à représenter des nombres avec des exigences strictes en matière de précision de calcul. Dans sa forme actuelle, notre nombre comporte 10 chiffres après la virgule. On veut en supprimer 7 et n'en garder que 3. En conséquence, en plus du chiffre 3, il faut passer le mode arrondi. BigDecimal a un total de 8 modes d'arrondi. C'est beaucoup! Mais si vous avez vraiment besoin d'affiner la précision de vos calculs, vous aurez tout ce dont vous avez besoin. Voici donc les 8 modes d'arrondi proposés par BigDecimal :
  1. ROUND_CEILING — arrondit au supérieur

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — arrondit vers zéro

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — arrondit à l'inférieur

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP — arrondit si le nombre après la virgule >= 0,5

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — arrondit si le nombre après la virgule > 0,5

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — l'arrondi dépend du nombre à gauche de la virgule décimale. Si le nombre à gauche est pair, l'arrondi sera inférieur. Si le nombre à gauche de la virgule décimale est impair, l'arrondi sera supérieur.

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    Le nombre à gauche de la décimale est 2 (pair). Le nombre est arrondi à l'inférieur. Nous voulons 0 décimales, donc le résultat est 2.

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    Le nombre à gauche de la virgule est 3 (impair). Le nombre est arrondi. Nous voulons 0 décimales, donc le résultat est 4.

  7. ROUND_UNNECCESSARY — Ce mode est utilisé lorsque vous devez passer un mode d'arrondi à une méthode, mais que le nombre n'a pas besoin d'être arrondi. Si vous essayez d'arrondir un nombre avec le mode ROUND_UNNECCESSARY défini, une ArithmeticException est levée.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — arrondit à partir de zéro.

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

Comparer de grands nombres

Ceci est également important. Vous vous souviendrez que nous utilisons la méthode equals () pour comparer des objets en Java. L'implémentation est soit fournie par le langage lui-même (pour les classes Java standard), soit remplacée par le programmeur. Mais dans le cas des objets BigDecimal , l'utilisation de la méthode equals() pour les comparaisons n'est pas recommandée. En effet, la méthode BigDecimal.equals() renvoie true uniquement si les 2 nombres ont la même valeur et la même échelle : Comparons le comportement de la méthode equals() pour les classes Double et BigDecimal :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
Sortie console:

true 
false
Comme vous pouvez le voir, pour BigDecimal , les nombres 1,5 et 1,50 se sont avérés inégaux ! C'était précisément à cause des spécificités de l'implémentation de la méthode equals() dans la classe BigDecimal. Pour une comparaison plus précise de deux objets BigDecimal , il est préférable d'utiliser la méthode compareTo() :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Sortie console:

0
La méthode compareTo() a renvoyé 0, ce qui signifie que 1,5 et 1,50 sont égaux. Et c'est le résultat que nous attendions ! :) Cela conclut notre leçon d'aujourd'hui. Il est maintenant temps de se remettre aux tâches! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION