Ci sono numeri che non sono rappresentabili nella base 10 ma possono essere rappresentati nella base 2?

40

C# ha il tipo decimal utilizzato per i numeri che richiedono un'esatta rappresentazione in base 10. Ad esempio, 0.1 non può essere rappresentato in base 2 (es. float e double ) e sarà sempre un'approssimazione se memorizzato in variabili che sono di questi tipi.

Mi stavo chiedendo se fosse possibile anche il fatto contrario. Ci sono numeri che non sono rappresentabili in base 10 ma possono essere rappresentati in base 2 (nel qual caso vorrei usare un float invece di un decimal per gestirli)?

    
posta Max 25.04.2014 - 17:27
fonte

3 risposte

103

Ecco la chiave del tuo dilemma: 10 è il prodotto di 2 e 5 . Puoi rappresentare qualsiasi numero esattamente in decimali di base 10 che è k * 1/2 n * 1/5 m dove k , n e m sono interi.

In alternativa formulato - 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 quel numero - avrà una parte ripetitiva. Per esempio 1/15 = 0.0666666666 .... perché 3 (15 = 3 * 5) non è un fattore di 10.

Quindi, tutto ciò che è in grado di essere rappresentato nella base 2 esattamente (k * 1/2 n ) può essere rappresentato 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 esattamente rappresentati in alcune basi, ma ci vuole più di un numero di cifre / bit da fare.

In binario, il numero 1/10 che è convenientemente 0,1 in decimale 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).

Diamo un'occhiata al 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         |          
       ------        | repeating
       1 0000        | block    
         1010        |          
       ------        |          
          1100       |          
          1010       |          
          ----       |          
            100  ----+          

Questo è esattamente lo stesso tipo di cosa che ottieni quando provi a fare la divisione lunga per 1/3.

1/10, quando fattorizzato è 1 / (2 1 * 5 1 ). Per la base 10 (o qualsiasi multiplo di 10), questo numero termina ed è noto come numero normale . Un'espansione decimale che si ripete è conosciuta come ripetendo i decimali , e quei numeri che vanno avanti all'infinito senza ripetizione sono numeri irrazionali.

La matematica dietro a questo approfondisce Piccolo teorema di Fermat ... e una volta che inizi a dire Fermat o teorema, diventa un Domanda Math.SE .

Are there numbers that are not representable in base 10 but can be represented in base 2?

La risposta è "no".

Quindi, a questo punto dovremmo essere tutti chiari che ogni espansione binaria a lunghezza fissa di un numero razionale può essere rappresentata come un'espansione decimale a lunghezza fissa.

Consente di esaminare più da vicino il decimale in C # che ci porta a Virgola mobile decimale in .NET e dato all'autore, accetto che questo è il modo in cui funziona.

The decimal type has the same components as any other floating point number: a mantissa, an exponent and a sign. As usual, the sign is just a single bit, but there are 96 bits of mantissa and 5 bits of exponent. However, not all exponent combinations are valid. Only values 0-28 work, and they are effectively all negative: the numeric value is sign * mantissa / 10exponent. This means the maximum and minimum values of the type are +/- (296-1), and the smallest non-zero number in terms of absolute magnitude is 10-28.

Indicherò subito che a causa di questa implementazione ci sono numeri nel tipo double che non possono essere rappresentati in decimal - quelli che sono fuori dall'intervallo. Double.Epsilon è 4.94065645841247e-324 che non può essere rappresentato in decimal , ma può in double .

Tuttavia, all'interno dell'intervallo che può rappresentare un decimale, ha più precisione rispetto ad altri tipi nativi e può rappresentarli senza errori.

Ci sono altri tipi in giro. Esiste un BigInteger in C # che può rappresentare un numero arbitrariamente ampio. Non c'è alcun equivalente a BigDecimal di Java (che può rappresentare numeri con cifre decimali fino a 2 cifre 32 lunghe - che è un intervallo considerevole) esattamente . Tuttavia, se fai un po 'di movimento puoi trovare le implementazioni a mano.

Ci sono alcune lingue che hanno anche un tipo di dati razionale che ti permette di rappresentare esattamente i razionali (in modo che 1 / 3 è in realtà 1/3).

Specificamente per C # e la scelta di float o razionale, mi riferirò a Jon Skeet dalla pinta fluttuante decimale in. NET :

Most business applications should probably be using decimal rather than float or double. My rule of thumb is that manmade values such as currency are usually better represented with decimal floating point: the concept of exactly 1.25 dollars is entirely reasonable, for example. For values from the natural world, such as lengths and weights, binary floating point types make more sense. Even though there is a theoretical "exactly 1.25 metres" it's never going to occur in reality: you're certainly never going to be able to measure exact lengths, and they're unlikely to even exist at the atomic level. We're used to there being a certain tolerance involved.

    
risposta data 25.04.2014 - 17:38
fonte
6

Una volta fuori dal range di valori accettabili, la risposta è sì. Detto questo, quasi tutto all'interno della gamma avrà una rappresentazione. C # Riferimento decimale Sebbene non specificato nella specifica, numeri irrazionali non può essere esattamente rappresentato (ad esempio, e 1 , pi, radice quadrata di 2, ecc.).

The decimal keyword denotes a 128-bit data type. Compared to floating-point types, the decimal type has a greater precision and a smaller range, which makes it suitable for financial and monetary calculations. The approximate range and precision for the decimal type are shown in the following table.

Precision: 28-29 significant digits

1 Grazie a MichaelT per avermi ricordato di un altro numero irrazionale.

    
risposta data 25.04.2014 - 17:35
fonte
1

Un tipo a virgola mobile di base-due sarebbe in grado di rappresentare con precisione molti valori che un tipo di base-dieci della stessa dimensione non poteva. Qualsiasi valore che sarebbe esattamente rappresentabile da un tipo di base 2 di qualche dimensione sarebbe esattamente rappresentabile in un tipo di base-dieci di dimensioni sufficienti. La dimensione richiesta per un tipo puramente-base-dieci per rappresentare tutti i valori di un numero in virgola mobile binario dipenderà dall'intervallo esponenziale del tipo binario; centinaia di bit per float o migliaia per double .

Detto questo, il tipo Decimal è abbastanza grande che sarebbe stato possibile renderlo utilizzabile come un tipo "universale" in grado di contenere il valore di qualsiasi altra primitiva numerica e fornire altre caratteristiche aggiuntive oltre (se nient'altro, usa un bit per indicare se il valore memorizzato è il risultato della conversione di double , e se quel bit è impostato, usa 64 bit per mantenere il valore in questione). Microsoft ha scelto di non farlo, comunque. Di conseguenza, la conversione di double in Decimal fallirà completamente per valori grandi, causerà il arrotondamento dei valori piccoli al 1E-28 più vicino. Inoltre, anche all'interno dell'intervallo dinamico di decimal , il metodo di conversione non sarà "round-trip". Ad esempio, la valutazione di 1.0 / 3.0 come double produrrà 0,3333333333333333148, ma la conversione in decimale produrrà 0,333333333333333m e la conversione in doppio produrrà 0,3333333333333329818.

    
risposta data 25.04.2014 - 19:30
fonte

Leggi altre domande sui tag