Niveau : | Elémentaire |
La classe java.lang.Math contient une série de méthodes et variables mathématiques. Comme la classe Math fait partie du package java.lang, elle est automatiquement importée. De plus, il n'est pas nécessaire de déclarer un objet de type Math car les méthodes sont toutes static.
Exemple ( code Java 1.1 ) : Calculer et afficher la racine carrée de 3 |
public class Math1 {
public static void main(java.lang.String[] args) {
System.out.println(" = " + Math.sqrt(3.0));
}
}
Ce chapitre contient plusieurs sections :
PI représente pi dans le type double ( 3,14159265358979323846 )
E représente e dans le type double ( 2,7182818284590452354 )
Exemple ( code Java 1.1 ) : |
public class Math2 {
public static void main(java.lang.String[] args) {
System.out.println(" PI = "+Math.PI);
System.out.println(" E = "+Math.E);
}
}
Les méthodes sin(), cos(), tan(), asin(), acos(), atan() sont déclarées : public static double fonctiontrigo(double angle)
Les angles doivent être exprimés en radians. Pour convertir des degrés en radian, il suffit de les multiplier par PI/180
max (n1, n2)
min (n1, n2)
Ces méthodes existent pour les types int, long, float et double : elles déterminent respectivement les valeurs maximales et minimales des deux paramètres.
Exemple ( code Java 1.1 ) : |
public class Math1 {
public static void main(String[] args) {
System.out.println(" le plus grand = " + Math.max(5, 10));
System.out.println(" le plus petit = " + Math.min(7, 14));
}
}
Résultat : |
le plus grand = 10
le plus petit = 7
La classe Math propose plusieurs méthodes pour réaliser différents arrondis.
Pour les types float et double, cette méthode ajoute 0,5 à l'argument et restitue la plus grande valeur entière (int) inférieure ou égale au résultat.
Exemple ( code Java 1.1 ) : |
public class Arrondis1 {
static double[] valeur = {-5.7, -5.5, -5.2, -5.0, 5.0, 5.2, 5.5, 5.7 };
public static void main(String[] args) {
for (int i = 0; i < valeur.length; i++) {
System.out.println("round("+valeur[i]+") = "+Math.round(valeur[i]));
}
}
}
Résultat : |
round(-5.7) = -6
round(-5.5) = -5
round(-5.2) = -5
round(-5.0) = -5
round(5.0) = 5
round(5.2) = 5
round(5.5) = 6
round(5.7) = 6
Cette méthode effectue la même opération mais renvoie un type double.
Exemple ( code Java 1.1 ) : |
public class Arrondis2 {
static double[] valeur = {-5.7, -5.5, -5.2, -5.0, 5.0, 5.2, 5.5, 5.7 };
public static void main(String[] args) {
for (int i = 0; i < valeur.length; i++) {
System.out.println("rint("+valeur[i]+") = "+Math.rint(valeur[i]));
}
}
}
Résultat : |
rint(-5.7) = -6.0
rint(-5.5) = -6.0
rint(-5.2) = -5.0
rint(-5.0) = -5.0
rint(5.0) = 5.0
rint(5.2) = 5.0
rint(5.5) = 6.0
rint(5.7) = 6.0
Cette méthode renvoie l'entier le plus proche inférieur ou égal à l'argument.
Exemple ( code Java 1.1 ) : |
public class Arrondis3 {
static double[] valeur = {-5.7, -5.5, -5.2, -5.0, 5.0, 5.2, 5.5, 5.7 };
public static void main(String[] args) {
for (int i = 0; i < valeur.length; i++) {
System.out.println("floor("+valeur[i]+") = "+Math.floor(valeur[i]));
}
}
}
Résultat : |
floor(-5.7) = -6.0
floor(-5.5) = -6.0
floor(-5.2) = -6.0
floor(-5.0) = -5.0
floor(5.0) = 5.0
floor(5.2) = 5.0
floor(5.5) = 5.0
floor(5.7) = 5.0
Cette méthode renvoie l'entier le plus proche supérieur ou égal à l'argument
Exemple ( code Java 1.1 ) : |
public class Arrondis4 {
static double[] valeur = {-5.7, -5.5, -5.2, -5.0, 5.0, 5.2, 5.5, 5.7 };
public static void main(String[] args) {
for (int i = 0; i < valeur.length; i++) {
System.out.println("ceil("+valeur[i]+") = "+Math.ceil(valeur[i]));
}
}
}
Résultat : |
ceil(-5.7) = -5.0
ceil(-5.5) = -5.0
ceil(-5.2) = -5.0
ceil(-5.0) = -5.0
ceil(5.0) = 5.0
ceil(5.2) = 6.0
ceil(5.5) = 6.0
ceil(5.7) = 6.0
Cette méthode donne la valeur absolue de x (les nombres négatifs sont convertis en leur opposé). La méthode est définie pour les types int, long, float et double.
Exemple ( code Java 1.1 ) : |
public class Math1 {
public static void main(String[] args) {
System.out.println(" abs(-5.7) = "+Math.abs(-5.7));
}
}
Résultat : |
abs(-5.7) = 5.7
Cette méthode renvoie le reste de la division du premier argument par le deuxième
Exemple ( code Java 1.1 ) : |
public class Math1 {
public static void main(String[] args) {
System.out.println(" reste de la division de 10 par 3 = "
+Math.IEEEremainder(10.0, 3.0) );
}
}
Résultat : |
reste de la division de 10 par 3 = 1.0
Cette méthode élève le premier argument à la puissance indiquée par le second.
Exemple ( code Java 1.1 ) : |
public static void main(java.lang.String[] args) {
System.out.println(" 5 au cube = "+Math.pow(5.0, 3.0) );
}
Résultat : |
5 au cube = 125.0
Cette méthode calcule la racine carrée de son paramètre.
Exemple ( code Java 1.1 ) : |
public static void main(java.lang.String[] args) {
System.out.println(" racine carrée de 25 = "+Math.sqrt(25.0) );
}
Résultat : |
racine carrée de 25 = 5.0
Cette méthode calcule l'exponentielle de l'argument
Exemple ( code Java 1.1 ) : |
public static void main(java.lang.String[] args) {
System.out.println(" exponentiel de 5 = "+Math.exp(5.0) );
}
Résultat : |
exponentiel de 5 = 148.4131591025766
Cette méthode calcule le logarithme naturel de l'argument
Exemple ( code Java 1.1 ) : |
public static void main(java.lang.String[] args) {
System.out.println(" logarithme de 5 = "+Math.log(5.0) );
}
Résultat : |
logarithme de 5 = 1.6094379124341003
La méthode random() renvoie un nombre aléatoire compris entre 0.0 et 1.0.
Exemple ( code Java 1.1 ) : |
public static void main(java.lang.String[] args) {
System.out.println(" un nombre aléatoire = "+Math.random() );
}
Résultat : |
un nombre aléatoire = 0.8178819778125899
La classe java.math.BigDecimal est incluse dans l'API Java depuis la version 5.0.
La classe BigDecimal qui hérite de la classe java.lang.Number permet de réaliser des calculs en virgule flottante avec une précision dans les résultats similaire à celle de l'arithmétique scolaire.
La classe BigDecimal permet ainsi une représentation exacte des valeurs ce que ne peuvent garantir les données primitives de type numérique flottant (float ou double). Les calculs en virgule flottante privilégient en effet la vitesse de calcul plutôt que la précision.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
public class CalculDouble {
public static void main(String[] args) {
double valeur = 10*0.09;
System.out.println(valeur);
}
}
Résultat : |
0.8999999999999999
Cependant certains calculs, notamment ceux relatifs à des aspects financiers par exemple, requièrent une précision particulière : ces calculs utilisent généralement une précision de deux chiffres.
La classe BigDecimal permet de réaliser de tels calculs en permettant d'avoir le contrôle sur la précision (nombre de décimales significatives après la virgule) et la façon dont l'arrondi est réalisé.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal {
public static void main(
String[] args) {
BigDecimal valeur1 = new BigDecimal("10");
BigDecimal valeur2 = new BigDecimal("0.09");
BigDecimal valeur = valeur1.multiply(valeur2);
System.out.println(valeur);
}
}
Résultat : |
0.90
De plus, la classe BigDecimal peut gérer des valeurs possédant plus de 16 chiffres significatifs après la virgule.
La classe BigDecimal propose de nombreux constructeurs qui attendent en paramètre la valeur en différents types.
Remarque : il est préférable d'utiliser le constructeur attendant en paramètre la valeur sous forme de chaîne de caractères.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal3 {
public static void main(String[] args) {
BigDecimal valeur1 = new BigDecimal(2.8);
BigDecimal valeur2 = new BigDecimal("2.8");
System.out.println("valeur1="+valeur1);
System.out.println("valeur2="+valeur2);
}
}
Résultat : |
valeur1=2.79999999999999982236431605997495353221893310546875
valeur2=2.8
Avec cette classe, il est parfois nécessaire de devoir créer une nouvelle instance de BigDecimal à partir de la valeur d'une autre instance de BigDecimal. Aucun constructeur de la classe BigDecimal n'attend en paramètre un objet de type BigDecimal : il est nécessaire d'utiliser le constructeur qui attend en paramètre la valeur sous la forme d'une chaîne de caractères et de lui passer en paramètre le résultat de l'appel de la méthode toString() de l'instance de BigDecimal encapsulant la valeur.
La classe BigDecimal propose de nombreuses méthodes pour réaliser des opérations arithmétiques sur la valeur qu'elle encapsule telles que add(), substract(), multiply(), divide(), min(), max(), pow(), remainder(), divideToIntegralValue(), ...
Le classe BigDecimal est immuable : la valeur qu'elle encapsule ne peut pas être modifiée. Toutes les méthodes qui effectuent une opération sur la valeur encapsulée retournent un nouvel objet de type BigDecimal qui encapsule le résultat de l'opération.
Une erreur courante est d'invoquer la méthode mais de ne pas exploiter le résultat de son exécution.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal7 {
public static void main(String[] args) {
BigDecimal valeur = new BigDecimal("10.5");
BigDecimal bonus = new BigDecimal("4.2");
valeur.add(bonus);
System.out.println("valeur=" + valeur);
valeur = valeur.add(bonus);
System.out.println("valeur=" + valeur);
}
}
Résultat : |
valeur=10.5
valeur=14.7
La méthode setScale() permet de spécifier la précision de la valeur et éventuellement le mode d'arrondi à appliquer. Elle retourne un objet de type BigDecimal correspondant aux caractéristiques fournies puisque l'objet BigDecimal est immuable.
C'est une bonne pratique de toujours préciser le mode d'arrondi car si un arrondi est nécessaire et que le mode d'arrondi n'est pas précisé alors une exception de type ArithmeticException est levée.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal4 {
public static void main(String[] args) {
BigDecimal valeur1 = new BigDecimal(2.8);
valeur1.setScale(1);
System.out.println("valeur1="+valeur1);
}
}
Résultat : |
Exception in thread "main" java.lang.ArithmeticException: Rounding necessary
at java.math.BigDecimal.divide(BigDecimal.java:1346)
at java.math.BigDecimal.setScale(BigDecimal.java:2310)
at java.math.BigDecimal.setScale(BigDecimal.java:2350)
at com.jmdoudoux.test.bigdecimal.CalculBigDecimal4.main(CalculBigDecimal4.java:10)
La classe BigDecimal propose plusieurs modes d'arrondis : ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_UNNECESSARY et ROUND_UP
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal5 {
public static void main(String[] args) {
BigDecimal valeur = null;
String strValeur = null;
strValeur = "0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_CEILING);
System.out.println("ROUND_CEILING "+strValeur+" : "+valeur.toString());
strValeur = "-0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_CEILING);
System.out.println("ROUND_CEILING "+strValeur+" : "+valeur.toString());
strValeur = "0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_DOWN);
System.out.println("ROUND_DOWN "+strValeur+" : "+valeur.toString());
strValeur = "0.228";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_DOWN);
System.out.println("ROUND_DOWN "+strValeur+" : "+valeur.toString());
strValeur = "-0.228";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_DOWN);
System.out.println("ROUND_DOWN "+strValeur+" : "+valeur.toString());
strValeur = "0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println("ROUND_FLOOR "+strValeur+" : "+valeur.toString());
strValeur = "-0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println("ROUND_FLOOR "+strValeur+" : "+valeur.toString());
strValeur = "0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("ROUND_HALF_UP "+strValeur+" : "+valeur.toString());
strValeur = "0.225";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("ROUND_HALF_UP "+strValeur+" : "+valeur.toString());
strValeur = "0.225";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
System.out.println("ROUND_HALF_DOWN "+strValeur+" : "+valeur.toString());
strValeur = "0.226";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_DOWN);
System.out.println("ROUND_HALF_DOWN "+strValeur+" : "+valeur.toString());
strValeur = "0.215";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_EVEN);
System.out.println("ROUND_HALF_EVEN "+strValeur+" : "+valeur.toString());
strValeur = "0.225";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_HALF_EVEN);
System.out.println("ROUND_HALF_EVEN "+strValeur+" : "+valeur.toString());
strValeur = "0.222";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_UP);
System.out.println("ROUND_UP "+strValeur+" : "+valeur.toString());
strValeur = "0.226";
valeur = (new BigDecimal(strValeur)).setScale(2, BigDecimal.ROUND_UP);
System.out.println("ROUND_UP "+strValeur+" : "+valeur.toString());
}
}
Résultat : |
ROUND_CEILING 0.222 : 0.23
ROUND_CEILING -0.222 : -0.22
ROUND_DOWN 0.222 : 0.22
ROUND_DOWN 0.228 : 0.22
ROUND_DOWN -0.228 : -0.22
ROUND_FLOOR 0.222 : 0.22
ROUND_FLOOR -0.222 : -0.23
ROUND_HALF_UP 0.222 : 0.22
ROUND_HALF_UP 0.225 : 0.23
ROUND_HALF_DOWN 0.225 : 0.22
ROUND_HALF_DOWN 0.226 : 0.23
ROUND_HALF_EVEN 0.215 : 0.22
ROUND_HALF_EVEN 0.225 : 0.22
ROUND_UP 0.222 : 0.23
ROUND_UP 0.226 : 0.23
Le mode d'arrondi doit aussi être précisé lors de l'utilisation de la méthode divide().
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal6 {
public static void main(String[] args) {
BigDecimal valeur = new BigDecimal("1");
System.out.println(valeur.divide(new BigDecimal("3")));
}
}
Résultat : |
Exception in thread "main" java.lang.ArithmeticException:
Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1514)
at com.jmdoudoux.test.bigdecimal.CalculBigDecimal6.main(CalculBigDecimal6.java:9)
Le même exemple en précisant le mode d'arrondi fonctionne parfaitement.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal6 {
public static void main(String[] args) {
BigDecimal valeur = new BigDecimal("1");
System.out.println(valeur.divide(new BigDecimal("3"),4,BigDecimal.ROUND_HALF_DOWN));
}
}
Résultat : |
0.3333
La précision et le mode d'arrondi doivent être choisis avec attention parce que leur choix peut avoir de grandes conséquences sur les résultats de calculs notamment si le résultat final est constitué de multiples opérations. Dans ce cas, il est préférable de garder la plus grande précision durant les calculs et de n'effectuer l'arrondi qu'à la fin.
Il faut être vigilent lors de la comparaison entre deux objets de type BigDecimal. La méthode equals() compare les valeurs mais en tenant compte de la précision. Ainsi, il est préférable d'utiliser la méthode compareTo() qui n'effectue la comparaison que sur la valeur.
Exemple : |
package com.jmdoudoux.test.bigdecimal;
import java.math.BigDecimal;
public class CalculBigDecimal8 {
public static void main(String[] args) {
BigDecimal valeur1 = new BigDecimal("10.00");
BigDecimal valeur2 = new BigDecimal("10.0");
System.out.println("valeur1.equals(valeur2) = "+valeur1.equals(valeur2));
System.out.println("valeur1.compareTo(valeur2) = "+(valeur1.compareTo(valeur2)==0));
}
}
Résultat : |
valeur1.equals(valeur2) = false
valeur1.compareTo(valeur2) = true
La méthode compareTo() renvoie 0 si les deux valeurs sont égales, renvoie -1 si la valeur de l'objet fourni en paramètre est plus petite et renvoie 1 si la valeur de l'objet fourni en paramètre est plus grande.
Il est possible de passer en paramètre de la méthode format() de la classe NumberFormat un objet de type BigDecimal : attention dans ce cas, le nombre de décimales est limité à 16.
Exemple formatage d'un BigDecimal avec un format monétaire : |
package com.jmdoudoux.test.bigdecimal;
import java.math.*;
import java.text.*;
import java.util.*;
public class CalculBigDecimal9 {
public static void main(String[] args) {
BigDecimal payment = new BigDecimal("1234.567");
NumberFormat n = NumberFormat.getCurrencyInstance(Locale.FRANCE);
String s = n.format(payment);
System.out.println(s);
}
}
Résultat : |
1 234,57 €
La mise en oeuvre de la classe BigDecimal est plutôt fastidieuse comparée à d'autres langages qui proposent un support natif d'un type de données décimal mais elle permet d'effectuer des calculs précis.
L'utilisation de la classe BigDecimal n'est recommandée que si une précision particulière est nécessaire car sa mise en oeuvre est coûteuse.