Quali tipi di numeri sono rappresentabili in virgola mobile?

Ho letto molto sui float, ma è tutto inutilmente coinvolto. Penso di aver capito tutto, ma c’è solo una cosa che mi piacerebbe sapere con certezza:

So che, le frazioni della forma 1/pow(2,n) , con n un numero intero, possono essere rappresentate esattamente nei numeri in virgola mobile. Ciò significa che se aggiungo 1/32 a se stesso 32 milioni di volte, 1,000,000 esattamente 1,000,000 .

Che dire di qualcosa come 1/(32+16) ? È uno sopra la sum di due poteri di due, funziona? O è 1/32+1/16 che funziona? È qui che sono confuso, quindi se qualcuno potesse chiarire che per me lo apprezzerei.

La regola può essere riassunta come segue:

  • Un numero può essere rappresentato esattamente in binario se la fattorizzazione primaria del denominatore contiene solo 2. (cioè il denominatore è un potere-di-due)

Quindi 1/(32 + 16) non è rappresentabile in binario perché ha un fattore 3 nel denominatore. Ma 1/32 + 1/16 = 3/32 è.

Detto questo, ci sono più restrizioni per essere rappresentabili in un tipo a virgola mobile. Ad esempio, hai solo 53 bit di mantissa in un double IEEE quindi 1/2 + 1/2^500 non è rappresentabile.

Quindi puoi fare una sum di poteri-di-due purché la gamma degli esponenti non superi più di 53 poteri.


Per generalizzare questo ad altre basi:

  • Un numero può essere rappresentato esattamente nella base 10 se la fattorizzazione primaria del denominatore consiste solo di 2 e 5.

  • Un numero razionale X può essere rappresentato esattamente nella base N se la fattorizzazione primaria del denominatore di X contiene solo i primi trovati nella fattorizzazione di N

Un numero finito può essere rappresentato nel formato IEEE 754 a doppia precisione comune se e solo se è uguale a M • 2 e per alcuni interi M ed e tale che -2 53 53 e -1074 ≤ e ≤ 971.

Per una precisione singola, -2 24 24 e -149 ≤ e ≤ 104.

Per la precisione doppia, queste sono conseguenze del fatto che il formato a doppia precisione utilizza 52 bit per memorizzare un significato e (che normalmente ha 53 bit a causa di un 1 implicito) e utilizza 11 bit per memorizzare un esponente. 11 bit codifica numeri da 0 a 2047, ma 0 e 2047 sono esclusi per scopi speciali e il numero codificato viene polarizzato di 1023, quindi rappresenta esponenti imparziali da -1022 a 1023. Tuttavia, questi esponenti imparziali sono per significati nell’intervallo [1, 2), e questi significati hanno frazioni. Per esprimere il significato e come numero intero, ho regolato l’intervallo di esponente per 52. La precisione singola è simile, con 23 bit per memorizzare un significante a 24 bit, 8 bit per l’esponente e un bias di 127.

Esprimere i numeri rappresentabili usando un intero volte una potenza di due piuttosto che il significato frazionario più comune e semplifica la teoria dei numeri e altri ragionamenti sulle proprietà a virgola mobile. L’ho usato in questa risposta perché permette che l’insieme di valori rappresentabili sia express in modo conciso.

I numeri in virgola mobile sono rappresentati letteralmente utilizzando il modulo:

 1.m * 2^e 

Dove 1.m è una frazione binaria ed e è un numero intero positivo o negativo.

In quanto tale, puoi rappresentare esattamente 1/32 + 1/16 , come:

 1.1000000 * 2^-4 

( 1.10 essendo la frazione binaria equivalente a 1.5.) 1/48 , tuttavia, non è rappresentabile in questo formato.

Un punto non ancora menzionato è che semanticamente, un numero in virgola mobile può essere considerato come rappresentativo di un intervallo di valori. L’intervallo di valori ha un punto centrale definito con precisione e la specifica IEEE generalmente richiede che il risultato di un calcolo a virgola mobile sia il numero il cui intervallo contiene il punto uno che otterrebbe operativo sui punti centrali dei numeri originali, ma nella sequenza:

   doppio N1 = 0,1;
   float N2 = (float) N1;
   doppio N3 = N2;

N2 è la rappresentazione univoca corretta e corretta del valore che era stata rappresentata in N1, nonostante il requisito sciocco del linguaggio di utilizzare un cast esplicito. N3 rappresenterà uno dei valori che N2 potrebbe rappresentare (le specifiche del linguaggio capita di scegliere il double valore il cui raggio è centrato al centro dell’intervallo del float ). Si noti che mentre N2 rappresenta il valore del suo tipo il cui intervallo contiene il valore corretto, N3 no.

Per inciso, la conversione di un numero da una stringa a una variabile in .net e .net sembra passare attraverso una conversione intermedia a double , che a volte può alterare il valore. Ad esempio, anche se il valore 13571357 è rappresentabile come un float a precisione singola, il valore 13571357.499999999069f viene arrotondato a 13571358 (anche se è ovviamente più vicino a 13571357).