1. Arrondir les nombres réels

Comme nous l'avons déjà mentionné, lorsqu'un nombre réel est attribué à une intvariable, il est toujours arrondi à l'entier inférieur le plus proche - la partie fractionnaire est simplement ignorée.

Mais il est facile d'imaginer une situation où un nombre fractionnaire doit être arrondi à l'entier le plus proche dans les deux sens ou même arrondi. Que faites-vous dans ce cas ?

Pour cela et pour de nombreuses situations similaires, Java a la Mathclasse, qui a les méthodes round(), ceil()et floor().


Math.round()méthode

La Math.round()méthode arrondit un nombre à l'entier le plus proche :

long x = Math.round(real_number)

Mais il y a une autre nuance ici : cette méthode renvoie un longentier (pas un int). Comme les nombres réels peuvent être très grands, les créateurs de Java ont décidé d'utiliser le plus grand type d'entier disponible de Java : long.

En conséquence, si un programmeur veut affecter le résultat à une intvariable, alors il doit indiquer explicitement au compilateur qu'il accepte la perte éventuelle de données (dans le cas où le nombre résultant ne rentre pas dans un inttype).

int x = (int) Math.round(real_number)

Exemples:

Déclaration Résultat
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()méthode

La Math.ceil()méthode arrondit un nombre à un nombre entier. Voici des exemples :

Déclaration Résultat
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()méthode

La Math.floor()méthode arrondit un nombre à un entier inférieur . Voici des exemples :

Déclaration Résultat
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Bien sûr, lorsque vous arrondissez un nombre à un nombre entier, il est plus facile d'utiliser simplement un opérateur de transtypage :(int)

Déclaration Résultat
int x = (int) 4.9
4

Si vous avez du mal à vous souvenir de ces noms, une courte leçon d'anglais vous aidera :

  • Mathsignifie mathématiques
  • Roundsignifie rond
  • Ceilingsignifie plafond
  • Floorsignifie plancher

2. Comment les nombres à virgule flottante sont structurés

Le doubletype peut stocker des valeurs comprises entre et . Cette vaste plage de valeurs (par rapport au type) s'explique par le fait que le type (ainsi que ) a une structure interne complètement différente des types entiers. En interne, le type encode sa valeur sous la forme de deux nombres : le premier est appelé la mantisse et le second est appelé l' exposant .-1.7*10308+1.7*10308intdoublefloatdouble

Disons que nous avons le nombre 123456789et que nous le stockons dans une doublevariable. Lorsque nous le faisons, le nombre est converti en , et en interne le type stocke deux nombres — et . Le significande ("partie significative du nombre" ou mantisse) est surligné en rouge, tandis que l'exposant est surligné en bleu.1.23456789*108double234567898

Cette approche permet de stocker à la fois de très grands nombres et de très petits. Mais comme la représentation du nombre est limitée à 8 octets (64 bits) et que certains bits sont utilisés pour stocker l' exposant (ainsi que le signe de la mantisse et le signe de l'exposant), le nombre maximal de chiffres disponibles pour représenter la mantisse est de 15 .

Ceci est une description très simplifiée de la façon dont les nombres réels sont structurés.


3. Perte de précision lorsque l'on travaille avec des nombres réels

Lorsque vous travaillez avec des nombres réels, gardez toujours à l'esprit que les nombres réels ne sont pas exacts . Il peut toujours y avoir des erreurs d'arrondi et des erreurs de conversion lors de la conversion de décimal en binaire. De plus, la source d'erreur la plus courante est la perte de précision lors de l'addition/soustraction de nombres sur des échelles radicalement différentes.

Ce dernier fait est un peu hallucinant pour les programmeurs novices.

Si nous soustrayons de , nous obtenons .1/109109109

Soustraire des nombres sur des échelles radicalement différentes Explication
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
Le deuxième nombre est extrêmement petit , ce qui fera que sa significande (surlignée en gris) sera ignorée. Les 15 chiffres significatifs sont surlignés en orange.

Que dire, la programmation n'est pas la même chose que les mathématiques.


4. Piège lors de la comparaison de nombres réels

Un autre danger guette les programmeurs lorsqu'ils comparent des nombres réels. Cela se produit lorsque vous travaillez avec des nombres réels, car les erreurs d'arrondi peuvent s'accumuler. Le résultat est qu'il existe des situations où l'on s'attend à ce que les nombres réels soient égaux, mais ils ne le sont pas. Ou vice versa : les nombres sont censés être différents, mais ils sont égaux.

Exemple:

Déclaration Explication
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
La valeur de la variable a sera 1000000000.0
La valeur de la variable c sera 1000000000.0
(le nombre dans la b variable est excessivement petit)

Dans l'exemple ci-dessus, aet cne devraient pas être égaux, mais ils le sont.

Ou prenons un autre exemple :

Déclaration Explication
double a = 1.00000000000000001;
double b = 1.00000000000000002;
La valeur de la variable a sera 1.0
La valeur de la variable b sera1.0

5. Un fait intéressant surstrictfp

Java a un mot-clé spécial (pointstrictfp flottant strict ) , qui ne se trouve pas dans d'autres langages de programmation . Et savez-vous pourquoi vous en avez besoin ? Cela aggrave la précision des opérations avec des nombres à virgule flottante. Voici l'histoire de la façon dont cela est arrivé:

Les créateurs de Java :
Nous voulons vraiment que Java soit super populaire et qu'il exécute des programmes Java sur autant d'appareils que possible. Nous nous sommes donc assurés que la spécification de la machine Java indique que tous les programmes doivent s'exécuter de la même manière sur tous les types d'appareils !
Fabricants de processeurs Intel :
Salut tout le monde! Nous avons amélioré nos processeurs, et maintenant tous les nombres réels sont représentés en utilisant 10 octets au lieu de 8 octets à l'intérieur de nos processeurs. Plus d'octets signifie plus de chiffres significatifs. Qu'est-ce que cela signifie? C'est exact! Désormais, vos calculs scientifiques seront encore plus précis !
Scientifiques et acteurs impliqués dans des calculs ultra-précis :
Cool! Bien joué. Excellente nouvelle!
Les créateurs de Java :
Non-non-non, les gars ! Nous vous avons déjà dit que tous les programmes Java doivent s'exécuter de la même manière sur tous les appareils . Nous allons désactiver de force la possibilité d'utiliser des nombres réels de 10 octets dans les processeurs Intel.
Maintenant tout va bien à nouveau ! Ne nous remerciez pas.
Scientifiques et acteurs impliqués dans des calculs ultra-précis :
Es-tu devenu complètement fou ? Remettez vite tout en l'état !
Les créateurs de Java :
Les gars, c'est pour votre bien ! Imaginez : tous les programmes Java fonctionnent de la même manière sur tous les appareils . Ce est tellement cool!
Scientifiques et acteurs impliqués dans des calculs ultra-précis :
Non. Ce n'est pas cool du tout. Remettez vite tout comme c'était ! Ou savez-vous où nous mettrons votre Java?
Les créateurs de Java :
Hmm. Pourquoi tu ne l'as pas dit tout de suite ? Bien sûr, nous le remettrons.
Nous avons restauré votre capacité à utiliser toutes les fonctionnalités des derniers processeurs.
Au fait... Nous avons également spécialement ajouté le strictfpmot-clé à la langue. Si vous l'écrivez avant le nom d'une fonction, alors toutes les opérations impliquant des nombres réels à l'intérieur de cette fonction seront également mauvaises sur tous les appareils !