30 aprile 2022

Numeri

Nella versione moderna di JavaScript ci sono due differenti tipi di numeri:

  1. I numeri regolari, che vengono memorizzati nel formato a 64 bit IEEE-754, conosciuti anche come “numeri in virgola mobile con doppia precisione”. Questi sono i numeri che utilizziamo la maggior parte del tempo, e sono quelli di cui parleremo in questo capitolo.

  2. I BigInt, che vengono utilizzati per rappresentare numeri interi di lunghezza arbitraria. Talvolta possono tornare utili, poiché i numeri regolari non possono eccedere 253 od essere inferiori di -253. Poiché i BigInt vengono utilizzati in alcune aree speciali, gli abbiamo dedicato un capitolo BigInt.

Quindi in questo capitolo parleremo dei numeri regolari.

Diversi modi di scrivere un numero

Immaginiamo di dover scrivere 1 milione. La via più ovvia è:

let billion = 1000000000;

Possiamo anche usare il carattere underscore _ come separatore:

let billion = 1_000_000_000;

Qui il carattere _ gioca il ruolo di “zucchero sintattico”, cioè rende il numero più leggibile. Il motore JavaScript semplicemente ignorerà i caratteri _ tra le cifre, quindi è equivalente al milione scritto sopra.

Nella vita reale però cerchiamo di evitare di scrivere lunghe file di zeri per evitare errori. E anche perché siamo pigri. Solitamente scriviamo qualcosa del tipo "1ml" per un milione o "7.3ml" 7 milioni e 300mila. Lo stesso vale per i numeri più grandi.

In JavaScript, possiamo abbreviare un numero inserendo la lettera "e" con il numero di zeri a seguire:

let billion = 1e9;  // 1 miliardo, letteralmente: 1 e 9 zeri

alert( 7.3e9 );  // 7.3 miliardi (equivale a 7300000000 o 7_300_000_000)

In altre parole, "e" moltiplica il numero 1 seguito dal numero di zeri dati.

1e3 = 1 * 1000 // e3 significa *1000
1.23e6 = 1.23 * 1000000 // e6 significa *1000000

Ora proviamo a scrivere qualcosa di molto piccolo. Ad esempio, 1 microsecondo (un milionesimo di secondo):

let ms = 0.000001;

Come prima, l’utilizzo di "e" può aiutare. Se volessimo evitare di scrivere esplicitamente tutti gli “0”, potremmo scrivere:

let ms = 1e-6; // sei zeri alla sinistra di 1

Se contiamo gli zeri in 0.000001, ce ne sono 6. Quindi ovviamente 1e-6.

In altre parole, un numero negativo dopo "e" significa una divisione per 1 seguito dal numero di zeri dati:

// -3 divide 1 con 3 zeri
1e-3 = 1 / 1000; // 0.001

// -6 divide 1 con 6 zeri
1.23e-6 = 1.23 / 1000000; // 0.00000123

Numeri esadecimali, binari e ottali

I numeri esadecimali (hexadecimal o hex) sono largamente utilizzati in JavaScript per rappresentare colori, codifiche di caratteri, e molte altre cose. Quindi ovviamente esiste un modo per abbreviarli: 0x e poi il numero.

Ad esempio:

alert( 0xff ); // 255
alert( 0xFF ); // 255 (equivalente)

I sistemi binario e ottale sono utilizzati raramente, ma sono comunque supportati con l’utilizzo dei prefissi 0b e 0o:

let a = 0b11111111; // forma binaria di 255
let b = 0o377; // forma ottale di 255

alert( a == b ); // true, lo stesso numero 255 da entrambe le parti

Ci sono solo 3 sistemi di numerazione con questo livello di supporto. Per gli altri sistemi, dovremmo utilizzare la funzione parseInt (che vedremo più avanti in questo capitolo).

toString(base)

Il metodo num.toString(base) ritorna una rappresentazione in stringa del numero num con il sistema di numerazione fornito base.

Ad esempio:

let num = 255;

alert( num.toString(16) );  // ff
alert( num.toString(2) );   // 11111111

La base può variare da 2 a 36. Di default vale 10.

Altri casi di uso comune sono:

  • base=16 si utilizza per colori in esadecimale, codifiche di caratteri, i caratteri supportati sono 0..9 o A..F.

  • base=2 viene utilizzato per debugging o operazioni bit a bit, i caratteri accettati sono 0 o 1.

  • base=36 la base massima, i caratteri possono andare da 0..9 o A..Z. L’intero alfabeto latino viene utilizzato per rappresentare un numero. Un caso divertente di utilizzo per la base 36 è quando abbiamo bisogno che un identificatore molto lungo diventi qualcosa di più breve, come ad esempio per accorciare gli url. Possiamo semplicemente rappresentarlo in base 36:

    alert( 123456..toString(36) ); // 2n9c
Due punti per chiamare un metodo

Da notare che i due punti in 123456..toString(36) non sono un errore. Se vogliamo chiamare un metodo direttamente da un numero, come toString nell’esempio sopra, abbiamo bisogno di inserire due punti ...

Se inseriamo un solo punto: 123456.toString(36), otterremo un errore, perché la sintassi JavaScript implica una parte decimale a seguire del primo punto. Se invece inseriamo un ulteriore punto, allora JavaScript capirà che la parte decimale è vuota e procederà nel chiamare il metodo.

Potremmo anche scrivere (123456).toString(36).

Arrotondare

Una delle operazioni più utilizzate quando lavoriamo con i numeri è l’arrotondamento.

Ci sono diverse funzioni integrate per eseguire questa operazione:

Math.floor
Arrotonda per difetto: 3.1 diventa 3, e -1.1 diventa -2.
Math.ceil
Arrotonda per eccesso: 3.1 diventa 4, e -1.1 diventa -1.
Math.round
Arrotonda all’intero più vicino: 3.1 diventa 3, 3.6 diventa 4, e 3.5 viene arrotondato anch’esso a 4.
Math.trunc (non supportato da Internet Explorer)
Rimuove tutto dopo la virgola decimale senza arrotondare: 3.1 diventa 3, -1.1 diventa -1.