En JavaScript moderne, il existe deux types de nombres :
-
Les nombres standards en JavaScript sont stockĂ©s au format 64 bits IEEE-754, Ă©galement connu sous le nom de ânombres Ă virgule flottante double prĂ©cisionâ. Ce sont des chiffres que nous utilisons le plus souvent, et nous en parlerons dans ce chapitre.
-
Les nombres BigInt pour représenter des entiers de longueur arbitraire. Ils sont parfois nécessaires, car un nombre régulier ne peut pas dépasser de maniÚre précise
253ou ĂȘtre infĂ©rieur Ă-253. Comme les bigints sont utilisĂ©s dans quelques zones spĂ©ciales, nous leur consacrons un chapitre spĂ©cial BigInt.
Nous allons donc parler ici des nombres réguliers. Développons nos connaissances à leur sujet.
Plus de façons dâĂ©crire un nombre
Imaginez que nous ayons besoin dâĂ©crire 1 milliard. Le moyen Ă©vident est :
let milliard = 1000000000;
Nous pouvons Ă©galement utiliser lâunderscore _ comme sĂ©parateur :
let billion = 1_000_000_000;
Ici, lâunderscore _ joue le rĂŽle de âsucre syntaxiqueâ, il rend le nombre plus lisible. Le moteur JavaScript ignore simplement _ entre les chiffres, donc câest exactement le mĂȘme milliard que ci-dessus.
Dans la vraie vie cependant, nous essayons dâĂ©viter dâĂ©crire de longues sĂ©quences de zĂ©ros. Nous sommes trop paresseux pour ça. Nous essaierons dâĂ©crire quelque chose comme â1 milliardâ pour un milliard ou â7,3 milliardsâ pour 7 milliards 300 millions. La mĂȘme chose est vraie pour la plupart des grands nombres.
En JavaScript, nous pouvons raccourcir un nombre en y ajoutant la lettre "e" et en spécifiant le nombre de zéros :
let milliard = 1e9; // 1 milliard, littéralement : 1 suivi de 9 zéros
alert( 7.3e9 ); // 7.3 milliards (pareil que 7300000000 ou 7_300_000_000)
En dâautres termes, e multiplie le nombre par 1 suivi du nombre de zĂ©ros spĂ©cifiĂ©.
1e3 === 1 * 1000 // e3 signifie *1000
1.23e6 === 1.23 * 1000000 // e6 signifie *1000000
Maintenant, écrivons quelque chose de trÚs petit. Disons, 1 microseconde (un millioniÚme de seconde) :
let us = 0.000001;
Comme avant, lâutilisation de "e" peut nous aider. Si nous voulons Ă©viter dâĂ©crire les zĂ©ros explicitement, nous pourrions dire la mĂȘme chose comme :
let us = 1e-6; // cinq zéros à gauche de 1
Si nous comptons les zĂ©ros dans 0.000001, il y en a 6. Donc logiquement, câest 1e-6.
En dâautres termes, un nombre nĂ©gatif aprĂšs "e" signifie une division par 1 suivi du nombre spĂ©cifiĂ© de zĂ©ros :
// -3 divise par 1 avec 3 zéros
1e-3 === 1 / 1000; // 0.001
// -6 divise par 1 avec 6 zéros
1.23e-6 === 1.23 / 1000000; // 0.00000123
// an example with a bigger number
1234e-2 === 1234 / 100; // 12.34, decimal point moves 2 times
Nombres hexadécimaux, binaires et octaux
Les nombres HexadĂ©cimaux sont souvent utilisĂ©s en JavaScript pour reprĂ©senter des couleurs, encoder des caractĂšres et pour beaucoup dâautres choses. Alors, naturellement, il existe un moyen plus court de les Ă©crire : 0x puis le nombre.
Par exemple :
alert( 0xff ); // 255
alert( 0xFF ); // 255 (mĂȘme rĂ©sultat car la casse n'a pas d'importance)
Les systÚmes numériques binaires et octaux sont rarement utilisés, mais sont également supportés avec les préfixes 0b et 0o :
let a = 0b11111111; // forme binaire de 255
let b = 0o377; // forme octale de 255
alert( a == b ); // true, car a et b valent le mĂȘme nombre, soit 255
Cependant ça ne fonctionne quâavec ces 3 systĂšmes de numĂ©ration. Pour les autres systĂšmes numĂ©rique, nous devrions utiliser la fonction parseInt (que nous verrons plus loin dans ce chapitre).
La méthode toString(base)
La méthode num.toString(base) retourne une chaßne de caractÚres représentant num dans le systÚme numérique de la base donnée.
Par exemple :
let num = 255;
alert( num.toString(16) ); // ff
alert( num.toString(2) ); // 11111111
La base peut varier de 2 Ă 36. Par dĂ©faut, il sâagit de 10.
Les cas dâutilisation courants sont :
-
base=16 est utilisĂ© pour les couleurs hexadĂ©cimales, les encodages de caractĂšres, etc. Les chiffres peuvent ĂȘtre
0..9ouA..F. -
base=2 est principalement utilisĂ© pour le dĂ©bogage dâopĂ©rations binaires, les chiffres pouvant ĂȘtre
0ou1. -
base=36 est le maximum, les chiffres peuvent ĂȘtre
0..9ouA..Z. Lâalphabet latin entier est utilisĂ© pour reprĂ©senter un nombre. Un cas amusant mais utile pour la base36consiste Ă transformer un identifiant numĂ©rique long en quelque chose de plus court, par exemple pour crĂ©er une URL courte. On peut simplement le reprĂ©senter dans le systĂšme numĂ©rique avec base36:alert( 123456..toString(36) ); // 2n9c
Veuillez noter que deux points sur 123456..toString(36) nâest pas une faute de frappe. Si nous voulons appeler une mĂ©thode directement sur un nombre, comme toString dans lâexemple ci-dessus, nous devons placer deux points .. avant la mĂ©thode.
Si nous plaçions un seul point : 123456.toString(36), il y aurait une erreur, car la syntaxe JavaScript applique la partie dĂ©cimale aprĂšs le premier point et il lirait toString(36) comme Ă©tant la partie dĂ©cimale de 123456 ce qui nâest pas le cas. Si nous plaçons un point de plus, alors JavaScript sait que la partie dĂ©cimale est vide et peut maintenant appliquer la mĂ©thode.
Il est aussi possible dâĂ©crire (123456).toString(36).
Arrondir
Arrondir est lâune des opĂ©rations les plus utilisĂ©es pour travailler avec des nombres.
Il existe plusieurs fonctions intégrées pour arrondir :
Math.floor- Arrondis vers le bas :
3.1devient3, et-1.1devient-2. Math.ceil- Arrondis ver le haut :
3.1devient4, et-1.1devient-1. Math.round- Arrondit Ă lâentier le plus proche :
3,1devient3,3,6devient4et pour le cas du milieu,3,5est Ă©galement arrondit Ă4. Math.trunc(non pris en charge par Internet Explorer)- Supprime tout ce qui suit le point dĂ©cimal :
3.1devient3,-1.1devient-1.
Voici le tableau pour résumer les différences entre eux :
Math.floor |
Math.ceil |
Math.round |
Math.trunc |
|
|---|---|---|---|---|
3.1 |
3 |
4 |
3 |
3 |
3.6 |
3 |
4 |
4 |
3 |
-1.1 |
-2 |
-1 |
-1 |
-1 |
-1.6 |
-2 |
-1 |
-2 |
-1 |
Ces fonctions couvrent toutes les maniĂšres possibles de traiter la partie dĂ©cimale dâun nombre. Mais que se passe-t-il si nous voulons arrondir le nombre Ă un certain chiffre aprĂšs la virgule ?
Par exemple, nous avons 1.2345 et voulons lâarrondir Ă 2 chiffres, pour obtenir seulement 1.23.
Il y a deux façons de le faire:
-
Multiplier et diviser.
Par exemple, pour arrondir le nombre au 2Ăšme chiffre aprĂšs la dĂ©cimale, nous pouvons multiplier le nombre par â100â, appeler la fonction dâarrondi puis le diviser.
let num = 1.23456; alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 -
La mĂ©thode toFixed(n) arrondit le nombre Ă
nchiffres aprĂšs le point et renvoie une chaĂźne de caractĂšres du rĂ©sultat.let num = 12.34; alert( num.toFixed(1) ); // "12.3"Ceci arrondit Ă la valeur la plus proche, similaire Ă
Math.round:let num = 12.36; alert( num.toFixed(1) ); // "12.4"Veuillez noter que le résultat de
toFixedest une chaĂźne de caractĂšres. Si la partie dĂ©cimale est plus courte quâindiquĂ©e, des zĂ©ros sont ajoutĂ©s Ă la fin :let num = 12.34; alert( num.toFixed(5) ); // "12.34000", ajout de zĂ©ros pour faire exactement 5 chiffresNous pouvons le convertir en un nombre en utilisant le plus unaire
+ou un appelNumber():+num.toFixed(5).
Calculs imprécis
En interne, un nombre est reprĂ©sentĂ© au format 64 bits IEEE-754, il y a donc exactement 64 bits pour stocker un nombre : 52 dâentre eux sont utilisĂ©s pour stocker les chiffres, 11 dâentre eux stockent la position du point dĂ©cimal (ils sont zĂ©ro pour les nombres entiers), et 1 bit est pour le signe.
Si un nombre est vraiment énorme, il peut déborder du stockage 64 bits et devenir une valeur numérique spéciale Infinity :
alert( 1e500 ); // infini
Ce qui est peut-ĂȘtre un peu moins Ă©vident, mais qui arrive souvent, est la perte de prĂ©cision.
ConsidĂ©rez ce (faux !) test dâĂ©galitĂ© :
alert( 0.1 + 0.2 == 0.3 ); // faux
Si on vérifie si la somme de 0.1 et 0.2 est égale à 0.3 on obtient faux.
Ătrange ! Quâest-ce que câest alors si ce nâest pas 0.3?
alert( 0.1 + 0.2 ); // 0.30000000000000004
Aie ! Imaginez que vous crĂ©iez un site dâe-commerce et que le visiteur mette des produits Ă 0,10 ⏠et 0,20 ⏠dans son panier. Le total de la commande sera de 0,30000000000000004 âŹ. Cela surprendrait nâimporte qui.
Mais pourquoi cela se produit-il ?
Un nombre est stocké en mémoire sous sa forme binaire, une séquence de uns et de zéros. Mais les fractions telles que 0.1, 0.2, qui semblent simples dans le systÚme numérique décimal, sont en réalité des fractions sans fin dans leur forme binaire.
En dâautres termes, quâest-ce que 0.1 ? Câest un divisĂ© par dix 1/10, un dixiĂšme. Dans le systĂšme numĂ©rique dĂ©cimal, ces nombres sont facilement reprĂ©sentables. Comparez-le Ă un tiers : 1/3. Cela devient une fraction sans fin 0.33333(3).
Ainsi, la division par puissances 10 est garantie de bien fonctionner dans le systĂšme dĂ©cimal, mais la division par 3 ne lâest pas. Pour la mĂȘme raison, dans le systĂšme de numĂ©ration binaire, la division par des puissances de 2 est garantie, mais 1/10 devient une fraction binaire sans fin.
Il nâexiste aucun moyen de stocker exactement 0.1 ou exactement 0.2 Ă lâaide du systĂšme binaire, tout comme il nâexiste aucun moyen de stocker un tiers sous forme de fraction dĂ©cimale.
Le format numĂ©rique IEEE-754 rĂ©sout ce problĂšme en arrondissant au nombre le plus proche possible. Ces rĂšgles dâarrondissement ne nous permettent normalement pas de voir cette âpetite perte de prĂ©cisionâ, mais elle existe.
Nous pouvons voir cela en action :
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
Et quand on additionne deux nombres, leurs âpertes de prĂ©cisionâ sâadditionnent.
Câest pourquoi 0.1 + 0.2 nâest pas exactement 0.3.
Le mĂȘme problĂšme existe dans de nombreux autres langages de programmation.
PHP, Java, C, Perl, Ruby donnent exactement le mĂȘme rĂ©sultat, car ils sont basĂ©s sur le mĂȘme format numĂ©rique.
Pouvons-nous contourner le problĂšme ? Bien sĂ»r, la mĂ©thode la plus fiable est dâarrondir le rĂ©sultat Ă lâaide dâune mĂ©thode toFixed(n):
let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // "0.30"
Veuillez noter que toFixed renvoie toujours une chaĂźne de caractĂšres. Il sâassure quâil a 2 chiffres aprĂšs le point dĂ©cimal. Câest pratique si nous avons un magasin en ligne et devons montrer 0.30$. Pour les autres cas, nous pouvons utiliser le plus unaire + pour le contraindre en un nombre :
let sum = 0.1 + 0.2;
alert( +sum.toFixed(2) ); // 0.3
Nous pouvons Ă©galement multiplier temporairement les nombres par 100 (ou un nombre plus grand) pour les transformer en nombres entiers, faire le calcul, puis rediviser. Ensuite, comme nous faisons des calculs avec des nombres entiers, lâerreur diminue quelque peu, mais nous lâobtenons toujours sur la division :
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
Ainsi, lâapproche multiplier/diviser rĂ©duit lâerreur, mais ne la supprime pas totalement.
Parfois, nous pourrions essayer dâĂ©viter les fractions complĂštement. Par exemple, si nous traitons avec un magasin, nous pouvons stocker les prix en cents au lieu de dollars. Mais que se passe-t-il si nous appliquons une rĂ©duction de 30 % ? En pratique, il est rarement possible dâĂ©viter totalement les fractions. Il suffit de les arrondir pour couper les âqueuesâ si nĂ©cessaire.
Essayez de lancer ceci :
// Bonjour! Je suis un nombre auto-croissant!
alert( 9999999999999999 ); // affiche 10000000000000000
La cause est encore une fois le manque de prĂ©cision. Le nombre comporte 64 bits, dont 52 peuvent ĂȘtre utilisĂ©s pour stocker des chiffres, mais cela ne suffit pas. Alors, les chiffres les moins significatifs disparaissent.
JavaScript ne dĂ©clenche pas dâerreur dans de tels Ă©vĂ©nements. il fait de son mieux pour adapter le nombre au format souhaitĂ©, mais malheureusement, ce format nâest pas assez grand.
Une autre consĂ©quence amusante de la reprĂ©sentation interne des nombres est lâexistence de deux zĂ©ros : 0 et -0.
Câest parce que le signe est reprĂ©sentĂ© par un bit, il peut donc ĂȘtre dĂ©fini ou non pour nâimporte quel nombre, y compris le zĂ©ro.
Dans le plupart des cas, la distinction est imperceptible, car les opĂ©rateurs peuvent les traiter de la mĂȘme maniĂšre.
Tests : isFinite et isNaN
Vous rappelez-vous de ces deux valeurs numériques spéciales ?
Infinite(et-Infinite) sont des valeurs numériques spéciales qui sont supérieures (inférieure) à tout.NaNreprésente une erreur.
Ils appartiennent au type number, mais ne sont pas des numĂ©ros ânormauxâ. Il existe donc des fonctions spĂ©ciales pour les vĂ©rifier :
-
isNaN(valeur)convertit son argument en un nombre et teste ensuite sâil estNaN:alert( isNaN(NaN) ); // true alert( isNaN("str") ); // trueMais avons-nous besoin de cette fonction ? Ne pouvons-nous pas simplement utiliser la comparaison
=== NaN? Malheureusement non. La valeurNaNest unique en ce sens quâelle ne vaut rien, y compris elle-mĂȘme :alert( NaN === NaN ); // false -
isFinite(valeur)convertit son argument en un nombre et renvoie true sâil sâagit dâun nombre rĂ©gulier, pas deNaN/Infinity/-Infinity:alert( isFinite("15") ); // true alert( isFinite("str") ); // false, car c'est une valeur non rĂ©guliĂšre: NaN alert( isFinite(Infinity) ); // false, car c'est aussi une valeur non rĂ©guliĂšre: Infinity
Parfois, isFinite est utilisé pour valider si une valeur de chaßne de caractÚres est un nombre régulier :
let num = +prompt("Entrez un nombre", '');
// sera vrai, sauf si vous entrez Infinity, -Infinity ou NaN
alert( isFinite(num) );
Veuillez noter quâune chaĂźne de caractĂšres vide ou une chaĂźne de caractĂšres contenant seulement des espaces est traitĂ©e comme 0 dans toutes les fonctions numĂ©rique, y compris isFinite.
Number.isNaN et Number.isFiniteLes mĂ©thodes Number.isNaN et Number.isFinite sont des versions plus âstrictesâ des fonctions isNaN et isFinite. Elles ne convertissent pas automatiquement leur argument en nombre, mais vĂ©rifient sâil appartient au type number.
-
Number.isNaN(value)retournetruesi lâargument appartient au typenumberet sâil vautNaN. Dans tous les autres cas, elle retournefalse.alert( Number.isNaN(NaN) ); // true alert( Number.isNaN("str" / 2) ); // true // Notez la diffĂ©rence : alert( Number.isNaN("str") ); // false, car "str" est de type "string" alert( isNaN("str") ); // true, car isNaN convertit la string "str" en un nombre et obtient NaN comme rĂ©sultatde la conversion -
Number.isFinite(value)retournetruesi lâargument appartient au typenumberet sâil vaut niNaN, niInfinity, ni-Infinity. Dans tous les autres cas, elle retournefalse.alert( Number.isFinite(123) ); // true alert( Number.isFinite(Infinity) ); // false alert( Number.isFinite(2 / 0) ); // false // Notez la diffĂ©rence : alert( Number.isFinite("123") ); // false, car "123" est de type "string" alert( isFinite("123") ); // true, car isFinite convertit la string "123" en un nombre 123
En quelque sorte, les fonction Number.isNaN et Number.isFinite sont plus simples et plus directes que les fonctions isNaN et isFinite. Cependant, en pratique isNaN et isFinite sont plus souvent utilisées car elles sont plus courtes à écrire.
Il existe une mĂ©thode intĂ©grĂ©e spĂ©ciale Object.is qui compare des valeurs telles que ===, mais qui est plus fiable pour deux cas extrĂȘmes :
- Cela fonctionne avec
NaN:Object.is(NaN, NaN) === true, câest une bonne chose. - Les valeurs
0et-0sont diffĂ©rentes :Object.is(0, -0) === false, techniquement câest vrai, car le numĂ©ro a en interne un bit de signe qui peut ĂȘtre diffĂ©rent mĂȘme si tous les autres bits sont Ă zĂ©ro.
Dans tous les autres cas, Object.is(a, b) est identique Ă a === b.
Nous mentionnons Object.is ici, car il est souvent utilisĂ© dans les spĂ©cifications JavaScript. Lorsquâun algorithme interne doit comparer deux valeurs pour ĂȘtre exactement identiques, il utilise Object.is (appelĂ© en interne SameValue).
parseInt et parseFloat
La conversion numĂ©rique Ă lâaide dâun plus + ou Number() est strict. Si une valeur nâest pas exactement un nombre, elle Ă©choue :
alert( +"100px" ); // NaN
La seule exception concerne les espaces au début ou à la fin de la chaßne de caractÚres, car ils sont ignorés.
Mais dans la vraie vie, nous avons souvent des valeurs en unitĂ©s, comme "100px" ou "12pt" en CSS. En outre, dans de nombreux pays, le symbole monĂ©taire se situe aprĂšs le montant. Nous avons donc "19âŹ" et souhaitons en extraire une valeur numĂ©rique.
Câest Ă quoi servent parseInt et parseFloat.
Ils âlisentâ un nombre dâune chaĂźne jusquâĂ ce quâils ne puissent plus. En cas dâerreur, le numĂ©ro rassemblĂ© est renvoyĂ©. La fonction parseInt renvoie un entier, tandis que parseFloat renvoie un nombre Ă virgule :
alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5
alert( parseInt('12.3') ); // 12, seule la partie entiÚre est renvoyée
alert( parseFloat('12.3.4') ); // 12.3, le deuxiĂšme point arrĂȘte la lecture
Il y a des situations oĂč parseInt / parseFloat retournera NaN. Cela arrive quand on ne peut lire aucun chiffre :
alert( parseInt('a123') ); // NaN, le premier symbole arrĂȘte le processus
parseInt(str, radix)La fonction parseInt() a un second paramĂštre optionnel. Il spĂ©cifie la base du systĂšme numĂ©rique, ce qui permet Ă parseInt dâanalyser Ă©galement les chaĂźnes de nombres hexadĂ©cimaux, binaires, etc. :
alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255, sans 0x cela fonctionne également
alert( parseInt('2n9c', 36) ); // 123456
Autres fonctions mathématiques
JavaScript a un objet Math intégré qui contient une petite bibliothÚque de fonctions et de constantes mathématiques.
Quelques exemples :
Math.random()-
Retourne un nombre aléatoire de 0 à 1 (1 non compris).
alert( Math.random() ); // 0.1234567894322 alert( Math.random() ); // 0.5435252343232 alert( Math.random() ); // ... (tout nombre aléatoire) Math.max(a, b, c...)etMath.min(a, b, c...)-
Renvoie le plus grand et le plus petit dâun nombre arbitraire dâarguments.
alert( Math.max(3, 5, -10, 0, 1) ); // 5 alert( Math.min(1, 2) ); // 1 Math.pow(n, power)-
Renvoie
nélevé à la puissancepowerdonnée.alert( Math.pow(2, 10) ); // 2 puissance 10 = 1024
Il y a plus de fonctions et de constantes dans lâobjet Math, y compris la trigonomĂ©trie, que vous pouvez trouver dans la documentation de lâobjet Math.
Résumé
Pour écrire des nombres avec beaucoup de zéros :
- Ajoutez
"e"avec le nombre de zéros au nombre. Comme123e6est123avec 6 zéros soit123000000. - Un nombre négatif aprÚs le
"e"entraßne la division du nombre par 1 suivi par le nombre de zéros donnés. Comme123-e6est123divisé par 1 suivi de 6 zéros, soit0.000123(123millioniÚmes).
Pour différents systÚmes de numération :
- Il est possible dâĂ©crire des nombres directement dans les systĂšmes hex (
0x), octal (0o) et binaire (0b). parseInt(str, base)passe la chaßne de caractÚresstrvers un systÚme numérique avec unebasedonnée :2 †base †36.num.toString(base)convertit un nombre en chaßne de caractÚres dans le systÚme numérique de labasedonnée.
Pour les tests de nombres réguliers :
isNaN(value)convertit son argument en nombre puis vĂ©rifie sâil sâagit deNaN.Number.isNaN(value)vĂ©rifie si son argument appartient au typenumberet, si câest le cas, vĂ©rifie sâil sâagit deNaN.isFinite(value)convertit son argument en nombre puis vĂ©rifie sâil ne sâagit pas deNaN/Infinity/-Infinity.Number.isFinite(value)vĂ©rifie si son argument appartient au typenumberet, si câest le cas, vĂ©rifie sâil ne sâagit pas deNaN/Infinity/-Infinity.
Pour convertir des valeurs telles que 12pt et 100px en nombres :
- Utiliser
parseInt/parseFloatpour la conversion âsoftâ, qui lit un nombre Ă partir dâune chaĂźne de caractĂšres, puis renvoie la valeur quâil pouvait lire avant de rencontrer une erreur.
Pour les fractions :
- Arrondissez en utilisant
Math.floor,Math.ceil,Math.trunc,Math.roundounum.toFixed(précision). - Assurez-vous de ne pas perdre de précision lorsque vous travaillez avec des fractions.
Plus de fonctions mathématiques :
- Voir lâobjet Math quand vous en avez besoin. La bibliothĂšque est trĂšs petite, mais peut couvrir les besoins de base.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)