Dart



Dati: i numeri          

Dart ci propone una classe stratta come "radice" di tutti i suoi valori numerici: tale classe si chiama num. Da essa discendono int e float. Il primo riguarda ovviamente i numeri interi che possono essere di grandezza arbitraria, mentre il secondo definisce numeri con virgola su 64 bit, ovvero in doppia precisione, fedele, come tutti i linguaggi, alle specifiche IEEE 754.
Partiamo quindi con qualche considerazione generale illustrando le operazioni di base:

  Esempio 2.1
1
2
3
4
5
6
7
8
9
10
11

import 'dart:math' as math;
void main() {
var
x = 3;
var
y = 5;
print(x + y);
print(x -
5);
print(x * y);
print(x / y);
print(x % y);
print(math.pow(x,y));

}


Non c'è bisogno di molte spiegazioni su buona parte di questo esempio, sono presentate le 4 operazioni basilari dell'aritmetica e, alla riga 8, l'operazione per ottenere il resto di una divisione. La riga 1 invece è importante in quanto ci presenta il modo per includere librerie esterne al core del linguaggio cosa che viene fatta tramite la keyword import, seguita dal nome della libreria e da un alias. In questo caso la libreria è quella matematica dart:math che conteniene molte funzioni utili, come ad esempio pow, che realizza l'elevamento a potenza nella forma
pow(base, esponente)
ed anche alcune costanti matematiche classiche. Ad esempio:

  Esempio 2.2
1
2
3
4
5

import 'dart:math' as math;

void main() {

print(math.PI);

print(math.SQRT1_2);

}


dove la riga 4 e la 5 espongono rispettivamente il famoso π e la radice quadrata di 1/2. Altre funzioni presenti in dart:math sono quelle classiche trigonometriche, logaritmiche, minimo e massimo. Torneremo a parlare delle librerie, numerose e che coprono un'ampia gamma di problematiche in un'apposita sezione di questo piccolo corso.
Tra le altre cose avrete notato che alla riga 8 dell'esempio 2.1 la divisione di 3 per 5 restituisce 0.6. Ottima cosa.... siamo negli anni 2000, 3/5 non fa 0, fa 0.6. Tuttavia, in qualche caso, è necessario estrapolare il risultato "intero" cioè quello che restituiscono quasi tutti i linguaggi di programmazione quando usate l'operatore di divisione. Per ottenere questo in abbiamo una seconda opzione di divisone che si attiva tramite l'operatore ~/. Quindi:

print(3 ~/ 5) vi restituirà un lapidario 0.

Tale operatore funziona anche con i numeri in virgola.

Tra gli operatori utilizzabili sui numeri troviamo anche ++ e -- che corrispondono rispettivamente all'incremento e al decremento di una unità del valore a cui sono applicati.

3++ vale 4 e così pure ++3 mentre --3 vale 2 e lo stesso valore assume 3--. Esiste una differenza tuttavia tra istruzioni che danno lo stesso risultato finale e la vedremo più avanti.

Concludiamo con una serie di operatori aventi in realtà una valenza più generale, nel senso si possono applicare ad altri tipi:

Operatore Uso
== uguaglianza
!= diverso da
< minore
> maggiore
<= minore o uguale
>= maggiore o uguale

Abbiamo detto che gli interi possono avere una grandezza a piacere. La cosa non è però così monolitica perchè in realtà, all'interno della macchina virtuale di Dart, essi hanno una rappresentazione diversificata a seconda della magnitudine, per ragioni di performance. Per la precisione abbiamo:

smi = small integer che hanno un range che va da -2^30 a 2^30-1 su sistemi 32 bit e da -2^62 a 2^62-1 su sistemi a 64 bit
mint = medium integer con range da -2^63 a 2^63-1
bigint = biginteger i cui limiti nei due sensi sono fissati solo dalla capacità rappresentativa della RAM del computer.

quando un numero è troppo grande per stare in un certo tipo di rappresentazione passa a quello immediatamente superiore che lo possa contenere. In partenza, se possibile, i numeri internamente sono tutti smi. Ovviamente ogni cambio di categoria è trasparente all'utente.

Un problema comune riguarda il rapporto tra stringhe e numeri. Oppure meglio, tra input da tastiera, che viene interpretato come di norma i formato stringa e numeri. In Dart il problema della convesione da stringa a numero è risolto molto semplicemente tramite l'uso di due metodi dedicati:

int.parse() che converte una stringa in intero
double.parse() che converte una stringa in un double

esistono certe regole ulteriori valide soprattutto per il primo:

--- è lecito inserire un '+' o un '-' in testa alla stringa da convertire al fine di specificare il segno
--- tramite radix si può specificare la radice del numero
--- premettere 0x in una stringa rende il numero esadecimale
--- per i double è ammesso che la stringa rappresenti un numero in formato esponenziale.

Vediamo l'esempio:

  Esempio 2.3
1
2
3
4
5
6
7

main() {

  print(int.parse('231'));

  print(int.parse('0x12f'));

  print(int.parse('777', radix: 8));

  print(double.parse('1.234'));

  print(double.parse('2.3411111e5'));

  }


Il problema inverso si risolve attraverso alcuni metodi dedicati. Il più immediato è toString:

1234.toString()

Se si vuole specificare il numero di cifre significative abbiamo toStringAsPrecision mentre con toStringAsFixed  precisa le cifre decimali significative. Interessante è toStringAsExponential che traduce il numero in formato esponenziale. Anche in questo caso è possibile specificare una radice, esattamente come vediamo nell'esempio seguente:

  Esempio 2.4
1
2
3
4
5
6
7
main() {
print(1234.toString() + "#");
print(1234.toStringAsPrecision(10));
print(1234.toStringAsFixed(10));
print(1234.toStringAsExponential(5) + "#");
print(64.toRadixString(2));
}

Le righe 2 e 5 ci permettono di apprezzare la concatenazione di due stringhe effettuata col simbolo +.