En JavaScript moderne, il existe deux types de nombres :
-
Les nombres standards en JavaScript sont stocks au format 64 bits IEEE-754, galement connu sous le nom de nombres virgule flottante double prcision. Ce sont des chiffres que nous utilisons le plus souvent, et nous en parlerons dans ce chapitre.
-
Les nombres BigInt pour reprsenter des entiers de longueur arbitraire. Ils sont parfois ncessaires, car un nombre rgulier ne peut pas dpasser de manire prcise
253ou tre infrieur-253. Comme les bigints sont utiliss dans quelques zones spciales, nous leur consacrons un chapitre spcial BigInt.
Nous allons donc parler ici des nombres rguliers. Dveloppons nos connaissances leur sujet.
Plus de faons dcrire un nombre
Imaginez que nous ayons besoin dcrire 1 milliard. Le moyen vident est :
let milliard = 1000000000;
Nous pouvons galement utiliser lunderscore _ comme sparateur :
let billion = 1_000_000_000;
Ici, lunderscore _ joue le rle de sucre syntaxique, il rend le nombre plus lisible. Le moteur JavaScript ignore simplement _ entre les chiffres, donc cest exactement le mme milliard que ci-dessus.
Dans la vraie vie cependant, nous essayons dviter dcrire de longues squences de zros. Nous sommes trop paresseux pour a. Nous essaierons dcrire quelque chose comme 1 milliard pour un milliard ou 7,3 milliards pour 7 milliards 300 millions. La mme chose est vraie pour la plupart des grands nombres.
En JavaScript, nous pouvons raccourcir un nombre en y ajoutant la lettre "e" et en spcifiant le nombre de zros :
let milliard = 1e9; // 1 milliard, littralement : 1 suivi de 9 zros
alert( 7.3e9 ); // 7.3 milliards (pareil que 7300000000 ou 7_300_000_000)
En dautres termes, e multiplie le nombre par 1 suivi du nombre de zros spcifi.
1e3 === 1 * 1000 // e3 signifie *1000
1.23e6 === 1.23 * 1000000 // e6 signifie *1000000
Maintenant, crivons quelque chose de trs petit. Disons, 1 microseconde (un millionime de seconde) :
let us = 0.000001;
Comme avant, lutilisation de "e" peut nous aider. Si nous voulons viter dcrire les zros explicitement, nous pourrions dire la mme chose comme :
let us = 1e-6; // cinq zros gauche de 1
Si nous comptons les zros dans 0.000001, il y en a 6. Donc logiquement, cest 1e-6.
En dautres termes, un nombre ngatif aprs "e" signifie une division par 1 suivi du nombre spcifi de zros :
// -3 divise par 1 avec 3 zros
1e-3 === 1 / 1000; // 0.001
// -6 divise par 1 avec 6 zros
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 hexadcimaux, binaires et octaux
Les nombres Hexadcimaux sont souvent utiliss en JavaScript pour reprsenter des couleurs, encoder des caractres et pour beaucoup dautres choses. Alors, naturellement, il existe un moyen plus court de les crire : 0x puis le nombre.
Par exemple :
alert( 0xff ); // 255
alert( 0xFF ); // 255 (mme rsultat car la casse n'a pas d'importance)
Les systmes numriques binaires et octaux sont rarement utiliss, mais sont galement supports avec les prfixes 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 mme nombre, soit 255
Cependant a ne fonctionne quavec ces 3 systmes de numration. Pour les autres systmes numrique, nous devrions utiliser la fonction parseInt (que nous verrons plus loin dans ce chapitre).
La mthode toString(base)
La mthode num.toString(base) retourne une chane de caractres reprsentant num dans le systme numrique de la base donne.
Par exemple :
let num = 255;
alert( num.toString(16) ); // ff
alert( num.toString(2) ); // 11111111
La base peut varier de 2 36. Par dfaut, il sagit de 10.
Les cas dutilisation courants sont :
-
base=16 est utilis pour les couleurs hexadcimales, les encodages de caractres, etc. Les chiffres peuvent tre
0..9ouA..F. -
base=2 est principalement utilis pour le dbogage doprations binaires, les chiffres pouvant tre
0ou1. -
base=36 est le maximum, les chiffres peuvent tre
0..9ouA..Z. Lalphabet latin entier est utilis pour reprsenter un nombre. Un cas amusant mais utile pour la base36consiste transformer un identifiant numrique long en quelque chose de plus court, par exemple pour crer une URL courte. On peut simplement le reprsenter dans le systme numrique avec base36:alert( 123456..toString(36) ); // 2n9c
Veuillez noter que deux points sur 123456..toString(36) nest pas une faute de frappe. Si nous voulons appeler une mthode directement sur un nombre, comme toString dans lexemple ci-dessus, nous devons placer deux points .. avant la mthode.
Si nous plaions un seul point : 123456.toString(36), il y aurait une erreur, car la syntaxe JavaScript applique la partie dcimale aprs le premier point et il lirait toString(36) comme tant la partie dcimale de 123456 ce qui nest pas le cas. Si nous plaons un point de plus, alors JavaScript sait que la partie dcimale est vide et peut maintenant appliquer la mthode.
Il est aussi possible dcrire (123456).toString(36).
Arrondir
Arrondir est lune des oprations les plus utilises pour travailler avec des nombres.
Il existe plusieurs fonctions intgres 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 lentier le plus proche :
3,1devient3,3,6devient4et pour le cas du milieu,3,5est galement arrondit4. Math.trunc(non pris en charge par Internet Explorer)- Supprime tout ce qui suit le point dcimal :
3.1devient3,-1.1devient-1.
Voici le tableau pour rsumer les diffrences 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 manires possibles de traiter la partie dcimale dun nombre. Mais que se passe-t-il si nous voulons arrondir le nombre un certain chiffre aprs la virgule ?
Par exemple, nous avons 1.2345 et voulons larrondir 2 chiffres, pour obtenir seulement 1.23.
Il y a deux faons de le faire:
-
Multiplier et diviser.
Par exemple, pour arrondir le nombre au 2me chiffre aprs la dcimale, nous pouvons multiplier le nombre par 100, appeler la fonction darrondi puis le diviser.
let num = 1.23456; alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 -
La mthode toFixed(n) arrondit le nombre
nchiffres aprs le point et renvoie une chane de caractres du rsultat.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 rsultat de
toFixedest une chane de caractres. Si la partie dcimale est plus courte quindique, des zros sont ajouts la fin :let num = 12.34; alert( num.toFixed(5) ); // "12.34000", ajout de zros pour faire exactement 5 chiffresNous pouvons le convertir en un nombre en utilisant le plus unaire
+ou un appelNumber():+num.toFixed(5).
Calculs imprcis
En interne, un nombre est reprsent au format 64 bits IEEE-754, il y a donc exactement 64 bits pour stocker un nombre : 52 dentre eux sont utiliss pour stocker les chiffres, 11 dentre eux stockent la position du point dcimal (ils sont zro pour les nombres entiers), et 1 bit est pour le signe.
Si un nombre est vraiment norme, il peut dborder du stockage 64 bits et devenir une valeur numrique spciale Infinity :
alert( 1e500 ); // infini
Ce qui est peut-tre un peu moins vident, mais qui arrive souvent, est la perte de prcision.
Considrez ce (faux !) test dgalit :
alert( 0.1 + 0.2 == 0.3 ); // faux
Si on vrifie si la somme de 0.1 et 0.2 est gale 0.3 on obtient faux.
trange ! Quest-ce que cest alors si ce nest pas 0.3?
alert( 0.1 + 0.2 ); // 0.30000000000000004
Aie ! Imaginez que vous criez un site de-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 nimporte qui.
Mais pourquoi cela se produit-il ?
Un nombre est stock en mmoire sous sa forme binaire, une squence de uns et de zros. Mais les fractions telles que 0.1, 0.2, qui semblent simples dans le systme numrique dcimal, sont en ralit des fractions sans fin dans leur forme binaire.
En dautres termes, quest-ce que 0.1 ? Cest un divis par dix 1/10, un dixime. Dans le systme numrique dcimal, ces nombres sont facilement reprsentables. 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 systme dcimal, mais la division par 3 ne lest pas. Pour la mme raison, dans le systme de numration binaire, la division par des puissances de 2 est garantie, mais 1/10 devient une fraction binaire sans fin.
Il nexiste aucun moyen de stocker exactement 0.1 ou exactement 0.2 laide du systme binaire, tout comme il nexiste aucun moyen de stocker un tiers sous forme de fraction dcimale.
Le format numrique IEEE-754 rsout ce problme en arrondissant au nombre le plus proche possible. Ces rgles darrondissement ne nous permettent normalement pas de voir cette petite perte de prcision, 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 prcision sadditionnent.
Cest pourquoi 0.1 + 0.2 nest pas exactement 0.3.
Le mme problme existe dans de nombreux autres langages de programmation.
PHP, Java, C, Perl, Ruby donnent exactement le mme rsultat, car ils sont bass sur le mme format numrique.
Pouvons-nous contourner le problme ? Bien sr, la mthode la plus fiable est darrondir le rsultat laide dune mthode toFixed(n):
let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // "0.30"
Veuillez noter que toFixed renvoie toujours une chane de caractres. Il sassure quil a 2 chiffres aprs le point dcimal. Cest 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, lerreur diminue quelque peu, mais nous lobtenons 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, lapproche multiplier/diviser rduit lerreur, mais ne la supprime pas totalement.
Parfois, nous pourrions essayer dviter les fractions compltement. 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 rduction de 30%? En pratique, il est rarement possible dviter totalement les fractions. Il suffit de les arrondir pour couper les queues si ncessaire.
Essayez de lancer ceci :
// Bonjour! Je suis un nombre auto-croissant!
alert( 9999999999999999 ); // affiche 10000000000000000
La cause est encore une fois le manque de prcision. Le nombre comporte 64 bits, dont 52 peuvent tre utiliss pour stocker des chiffres, mais cela ne suffit pas. Alors, les chiffres les moins significatifs disparaissent.
JavaScript ne dclenche pas derreur dans de tels vnements. il fait de son mieux pour adapter le nombre au format souhait, mais malheureusement, ce format nest pas assez grand.
Une autre consquence amusante de la reprsentation interne des nombres est lexistence de deux zros : 0 et -0.
Cest parce que le signe est reprsent par un bit, il peut donc tre dfini ou non pour nimporte quel nombre, y compris le zro.
Dans le plupart des cas, la distinction est imperceptible, car les oprateurs peuvent les traiter de la mme manire.
Tests : isFinite et isNaN
Vous rappelez-vous de ces deux valeurs numriques spciales ?
Infinite(et-Infinite) sont des valeurs numriques spciales qui sont suprieures (infrieure) tout.NaNreprsente une erreur.
Ils appartiennent au type number, mais ne sont pas des numros normaux. Il existe donc des fonctions spciales pour les vrifier :
-
isNaN(valeur)convertit son argument en un nombre et teste ensuite sil 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 quelle ne vaut rien, y compris elle-mme :alert( NaN === NaN ); // false -
isFinite(valeur)convertit son argument en un nombre et renvoie true sil sagit dun nombre rgulier, pas deNaN/Infinity/-Infinity:alert( isFinite("15") ); // true alert( isFinite("str") ); // false, car c'est une valeur non rgulire: NaN alert( isFinite(Infinity) ); // false, car c'est aussi une valeur non rgulire: Infinity
Parfois, isFinite est utilis pour valider si une valeur de chane de caractres est un nombre rgulier :
let num = +prompt("Entrez un nombre", '');
// sera vrai, sauf si vous entrez Infinity, -Infinity ou NaN
alert( isFinite(num) );
Veuillez noter quune chane de caractres vide ou une chane de caractres contenant seulement des espaces est traite comme 0 dans toutes les fonctions numrique, y compris isFinite.
Number.isNaN et Number.isFiniteLes mthodes 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 vrifient sil appartient au type number.
-
Number.isNaN(value)retournetruesi largument appartient au typenumberet sil vautNaN. Dans tous les autres cas, elle retournefalse.alert( Number.isNaN(NaN) ); // true alert( Number.isNaN("str" / 2) ); // true // Notez la diffrence : 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 rsultatde la conversion -
Number.isFinite(value)retournetruesi largument appartient au typenumberet sil 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 diffrence : 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 utilises car elles sont plus courtes crire.
Il existe une mthode intgre spciale Object.is qui compare des valeurs telles que ===, mais qui est plus fiable pour deux cas extrmes :
- Cela fonctionne avec
NaN:Object.is(NaN, NaN) === true, cest une bonne chose. - Les valeurs
0et-0sont diffrentes :Object.is(0, -0) === false, techniquement cest vrai, car le numro a en interne un bit de signe qui peut tre diffrent mme si tous les autres bits sont zro.
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 spcifications JavaScript. Lorsquun algorithme interne doit comparer deux valeurs pour tre exactement identiques, il utilise Object.is (appel en interne SameValue).
parseInt et parseFloat
La conversion numrique laide dun plus + ou Number() est strict. Si une valeur nest pas exactement un nombre, elle choue :
alert( +"100px" ); // NaN
La seule exception concerne les espaces au dbut ou la fin de la chane de caractres, car ils sont ignors.
Mais dans la vraie vie, nous avons souvent des valeurs en units, comme "100px" ou "12pt" en CSS. En outre, dans de nombreux pays, le symbole montaire se situe aprs le montant. Nous avons donc "19" et souhaitons en extraire une valeur numrique.
Cest quoi servent parseInt et parseFloat.
Ils lisent un nombre dune chane jusqu ce quils ne puissent plus. En cas derreur, le numro 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 entire est renvoye
alert( parseFloat('12.3.4') ); // 12.3, le deuxime point arrte 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 arrte le processus
parseInt(str, radix)La fonction parseInt() a un second paramtre optionnel. Il spcifie la base du systme numrique, ce qui permet parseInt danalyser galement les chanes de nombres hexadcimaux, binaires, etc. :
alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255, sans 0x cela fonctionne galement
alert( parseInt('2n9c', 36) ); // 123456
Autres fonctions mathmatiques
JavaScript a un objet Math intgr qui contient une petite bibliothque de fonctions et de constantes mathmatiques.
Quelques exemples :
Math.random()-
Retourne un nombre alatoire de 0 1 (1 non compris).
alert( Math.random() ); // 0.1234567894322 alert( Math.random() ); // 0.5435252343232 alert( Math.random() ); // ... (tout nombre alatoire) Math.max(a, b, c...)etMath.min(a, b, c...)-
Renvoie le plus grand et le plus petit dun nombre arbitraire darguments.
alert( Math.max(3, 5, -10, 0, 1) ); // 5 alert( Math.min(1, 2) ); // 1 Math.pow(n, power)-
Renvoie
nlev la puissancepowerdonne.alert( Math.pow(2, 10) ); // 2 puissance 10 = 1024
Il y a plus de fonctions et de constantes dans lobjet Math, y compris la trigonomtrie, que vous pouvez trouver dans la documentation de lobjet Math.
Rsum
Pour crire des nombres avec beaucoup de zros :
- Ajoutez
"e"avec le nombre de zros au nombre. Comme123e6est123avec 6 zros soit123000000. - Un nombre ngatif aprs le
"e"entrane la division du nombre par 1 suivi par le nombre de zros donns. Comme123-e6est123divis par 1 suivi de 6 zros, soit0.000123(123millionimes).
Pour diffrents systmes de numration :
- Il est possible dcrire des nombres directement dans les systmes hex (
0x), octal (0o) et binaire (0b). parseInt(str, base)passe la chane de caractresstrvers un systme numrique avec unebasedonne :2 base 36.num.toString(base)convertit un nombre en chane de caractres dans le systme numrique de labasedonne.
Pour les tests de nombres rguliers:
isNaN(value)convertit son argument en nombre puis vrifie sil sagit deNaN.Number.isNaN(value)vrifie si son argument appartient au typenumberet, si cest le cas, vrifie sil sagit deNaN.isFinite(value)convertit son argument en nombre puis vrifie sil ne sagit pas deNaN/Infinity/-Infinity.Number.isFinite(value)vrifie si son argument appartient au typenumberet, si cest le cas, vrifie sil ne sagit 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 dune chane de caractres, puis renvoie la valeur quil pouvait lire avant de rencontrer une erreur.
Pour les fractions :
- Arrondissez en utilisant
Math.floor,Math.ceil,Math.trunc,Math.roundounum.toFixed(prcision). - Assurez-vous de ne pas perdre de prcision lorsque vous travaillez avec des fractions.
Plus de fonctions mathmatiques :
- Voir lobjet Math quand vous en avez besoin. La bibliothque est trs 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)