Ecco la chiave del tuo dilemma: 10
è il prodotto di 2
e 5
. È possibile rappresentare qualsiasi numero esattamente in base 10 decimali che è k * 1/2 n * 1/5 m , dove k
, n
e m
sono interi.
In alternativa, se il numero n
in 1 / n contiene un fattore che non fa parte dei fattori della base, il numero non potrà essere rappresentato esattamente in un numero fisso di cifre nel binario / decimale / qualunque espansione di tale numero - avrà una parte ripetuta. Ad esempio 1/15 = 0,0666666666 .... perché 3 (15 = 3 * 5) non è un fattore 10.
Pertanto, qualsiasi cosa in grado di essere rappresentata esattamente nella base 2 (k * 1/2 n ) può essere rappresentata esattamente nella base 10.
Oltre a ciò, c'è il problema di quante cifre / bit stai usando per rappresentare il numero. Ci sono alcuni numeri che possono essere rappresentati esattamente in qualche base, ma ci vuole più di un certo numero di cifre / bit per fare.
In binario, il numero 1/10 che è convenientemente in decimale 0,1 non può essere rappresentato come un numero che può essere rappresentato in un numero fisso di bit in binario. Invece, il numero è 0,00011001100110011 ... 2 (con la parte 0011 che si ripete per sempre).
Consente di guardare il numero 1 2 /1010 2 un po 'più da vicino.
____
0,00011
+ ---------
1010 | 1.00000
0
-
1 0
0
----
1 00 --------- +
0 |
----- |
1 000 |
0 |
------ | ripetendo
1 0000 | bloccare
1010 |
------ |
1100 |
1010 |
---- |
100 ---- +
Questo è esattamente lo stesso tipo di cose che ottieni quando provi a fare la divisione lunga per 1/3.
1/10, quando il factoring è 1 / (2 1 * 5 1 ). Per la base 10 (o qualsiasi multiplo di 10), questo numero termina ed è noto come un numero normale . Un'espansione decimale che si ripete è nota come decimale ricorrente e quei numeri che vanno avanti all'infinito senza ripetersi sono numeri irrazionali.
La matematica dietro questo approfondisce il piccolo teorema di Fermat ... e una volta che si inizia a dire Fermat o teorema, diventa una domanda Math.SE .
Ci sono numeri che non sono rappresentabili nella base 10 ma possono essere rappresentati nella base 2?
La risposta è no'.
Quindi, a questo punto dovremmo essere tutti chiari sul fatto che ogni espansione binaria a lunghezza fissa di un numero razionale può essere rappresentata come espansione decimale a lunghezza fissa.
Vediamo più da vicino il decimale in C # che ci porta al punto decimale in .NET e dato l'autore, accetterò che sia così.
Il tipo decimale ha gli stessi componenti di qualsiasi altro numero in virgola mobile: una mantissa, un esponente e un segno. Come al solito, il segno è solo un singolo bit, ma ci sono 96 bit di mantissa e 5 bit di esponente. Tuttavia, non tutte le combinazioni di esponenti sono valide. Funzionano solo i valori 0-28 e sono effettivamente tutti negativi: il valore numerico è . Ciò significa che i valori massimo e minimo del tipo sono +/- (2 96 -1) e il numero minore diverso da zero in termini di magnitudine assoluta è 10 -28 .sign * mantissa / 10exponent
Sottolineerò subito che a causa di questa implementazione ci sono numeri nel double
tipo che non possono essere rappresentati decimal
- quelli che sono fuori dall'intervallo. Double.Epsilon
è 4.94065645841247e-324
che non può essere rappresentato in a decimal
, ma può in a double
.
Tuttavia, all'interno dell'intervallo che il decimale può rappresentare, ha più bit di precisione rispetto ad altri tipi nativi e può rappresentarli senza errori.
Ci sono altri tipi che fluttuano intorno. C'è un BigInteger in C # che può rappresentare un numero intero arbitrariamente grande. Non esiste un equivalente a BigDecimal di Java (che può rappresentare numeri con cifre decimali lunghe fino a 2 32 cifre - che è un intervallo considerevole) esattamente . Tuttavia, se cerchi un po 'in giro puoi trovare implementazioni arrotolate a mano.
Ci sono alcune lingue che hanno anche un tipo di dati razionale che consente di rappresentare esattamente i razionali (in modo che 1/3 sia effettivamente 1/3).
In particolare per C # e la scelta di float o razionale, rimanderò a Jon Skeet dalla pinta mobile decimale in .NET :
La maggior parte delle applicazioni aziendali dovrebbe probabilmente utilizzare decimale anziché float o double. La mia regola empirica è che i valori artificiali come la valuta sono generalmente meglio rappresentati con virgola mobile decimale: il concetto di esattamente 1,25 dollari è del tutto ragionevole, per esempio. Per i valori del mondo naturale, come lunghezze e pesi, i tipi binari a virgola mobile hanno più senso. Anche se esiste un teorico "esattamente 1,25 metri", nella realtà non accadrà mai: sicuramente non sarai mai in grado di misurare le lunghezze esatte, ed è improbabile che esistano anche a livello atomico. Siamo abituati a sostenere una certa tolleranza.