Perché i computer non memorizzano i numeri decimali come secondo numero intero?


24

I computer hanno difficoltà a memorizzare numeri frazionari in cui il denominatore è qualcosa di diverso da una soluzione a 2 ^ x. Questo perché la prima cifra dopo il decimale vale 1/2, la seconda 1/4 (o 1 / (2 ^ 1) e 1 / (2 ^ 2)) ecc.

Perché affrontare tutti i tipi di errori di arrotondamento quando il computer potrebbe aver appena memorizzato la parte decimale del numero come un altro numero intero (che è quindi accurato?)

L'unica cosa che mi viene in mente è occuparmi della ripetizione dei decimali (nella base 10), ma potrebbe esserci stata una soluzione marginale (come abbiamo attualmente con l'infinito).


8
Dovresti cercare come sono memorizzati i tipi decimali, a differenza dei tipi float / double.
Oded,

9
Non so come sia più preciso. La prima cifra dopo il decimale è 1/10, la seconda 1/100 ecc. Come è ancora più preciso avere ancora problemi di arrotondamento (come si rappresenta 1/3)? L'unica differenza è quali valori possono essere rappresentati esattamente.
Martin York,

17
Il virgola mobile decimale (che è ciò a cui ti riferisci due, solo in una rappresentazione più scomoda) non è più impreciso del virgola mobile binario. L'unica differenza è quali valori non possono essere rappresentati e poiché siamo abituati al sistema decimale non notiamo gli errori della versione decimale. E no, nessuno dei due può rappresentare tutti i numeri razionali e irrazionali.

1
Alla fine, si riduce all'efficienza. I computer sono binari e i circuiti per lavorare con questa rappresentazione binaria sono molto meno complessi. L'importanza di questo può essere un po 'diminuita oggi, ma ci fu un tempo in cui questo era molto significativo. Inoltre, qualsiasi rappresentazione tu scelga di memorizzare il tuo numero (in uno spazio finito) su un computer avrà un insieme finito di valori che può rappresentare e tutti mostreranno errori di arrotondamento con alcuni input. Il tipico formato a virgola mobile con Mantissa ed Exponent offre un intervallo molto maggiore quindi sarebbe possibile usare due numeri interi.
Mr.Mindor,

1
Consiglio vivamente di leggere alcuni degli articoli a cui fa riferimento la mia risposta alla domanda Cosa causa errori di arrotondamento in virgola mobile? che ho appena aggiornato con i dettagli dell'ultimo articolo della serie citata. In particolare, dai un'occhiata al motivo per cui il punto fisso non curerà i tuoi blues a virgola mobile .
Mark Booth,

Risposte:


35

In realtà ci sono modalità di numeri che lo fanno.

L'aritmetica decimale con codice binario (BCD) fa funzionare il computer in base 10. Il motivo per cui ci si imbatte raramente è che si spreca spazio: ogni singola cifra di un numero richiede un minimo di quattro bit, mentre un computer potrebbe altrimenti memorizzare fino a 16 valori in quello spazio. (Può anche essere più lento, ma è possibile avere una matematica BCD con accelerazione hardware che funzioni bene.). Questo è, infatti, esattamente ciò che fanno la maggior parte dei calcolatori, motivo per cui ci sono alcune classi di problemi di arrotondamento che non colpirai mai con un Casio da $ 5 che consumerà il tuo pranzo su un computer desktop.

L'altro percorso che puoi prendere è usare numeri razionali, cioè un numeratore e un denominatore, memorizzati come numeri interi. Questo è effettivamente disponibile in quasi tutte le lingue, è esatto e consente di archiviare tutto in formati binari nativi. Il problema è che, alla fine, gli utenti probabilmente non vogliono vedere frazioni come 463/13, e nemmeno 35 e 8/13. Vogliono vedere 35.615 ... e nel momento in cui arrivi lì, affronti tutti i problemi tipici. Aggiungete che questo formato occupa ancora più spazio e può essere significativamente più lento dell'aritmetica in virgola mobile e non troverete che nessun computer utilizzi questo formato per impostazione predefinita.

Quindi: i computer possono fare quello che vuoi, ma è lento e spreca spazio, quindi lo fanno solo quando devono davvero. Il resto del tempo, la velocità e il risparmio di spazio in virgola mobile sono un compromesso migliore.


Non intendi quattro bit (non byte) nel paragrafo BCD?

3
L'altra opzione è l'aritmetica in virgola fissa, in cui un numero intero rappresenta una frazione decimale se un numero, ad esempio la memorizzazione di valori monetari (senza calcoli che coinvolgono decimali o percentuale) dove 1 rappresenta $ 0,01.
mattnz,

1
@mattnz: True: i punti fissi sono un caso speciale di razionali.
Jon Purdy,

Fantastico, non sapevo che i calcolatori lo facessero.
SomeKittens,

3
C'è una terza opzione. Punto mobile con esponente decimale, come l' decimalimplementazione di C # : stackoverflow.com/a/5019178/174335 Non è un BCD in quanto non esiste una rappresentazione individuale di cifre decimali e non è un punto fisso.
Joren,

38

Esistono numerosi modi per memorizzare numeri frazionari e ciascuno di essi presenta vantaggi e svantaggi.

Il virgola mobile è di gran lunga il formato più popolare. Funziona codificando un segno, una mantissa e un esponente di base-2 firmato in numeri interi e impacchettandoli in un mucchio di bit. Ad esempio, potresti avere una mantissa a 32 bit di 0.5(codificata come 0x88888888) e un esponente a 32 bit con segno di +3( 0x00000003), che decodificherà in 4.0(0.5 * 2 ^ 3). I numeri in virgola mobile sono veloci, poiché sono implementati nell'hardware e la loro precisione si ridimensiona con dimensioni assolute, ovvero più piccolo è il numero, migliore è la precisione assoluta, quindi l'errore di arrotondamento relativo rimane costante con dimensioni assolute. I float sono eccellenti per i valori campionati da un dominio continuo, come lunghezze, livelli di pressione sonora, livelli di luce, ecc., E per questo motivo, sono comunemente usati nell'elaborazione di audio e immagini, nonché nell'analisi statistica e nelle simulazioni fisiche. Il loro più grande svantaggio è che non sono esatti, cioè sono inclini a errori di arrotondamento e non possono rappresentare accuratamente tutte le frazioni decimali. Tutti i linguaggi di programmazione tradizionali hanno una virgola mobile di qualche tipo.

Punto fissofunziona usando numeri interi sufficientemente grandi e riservando implicitamente una parte dei loro bit per la parte frazionaria. Ad esempio, un numero a virgola fissa a 24,8 bit riserva 24 bit per la parte intera (incluso il segno) e 8 bit per la parte frazionaria. Spostando a destra quel numero di 8 bit ci dà la parte intera. I numeri a virgola fissa erano molto diffusi quando le unità hardware a virgola mobile erano insolite o almeno molto più lente delle loro controparti intere. Mentre i numeri a virgola fissa sono in qualche modo più facili da gestire in termini di esattezza (anche solo perché sono più facili da ragionare), sono inferiori ai galleggianti in praticamente ogni altro aspetto - hanno meno precisione, un intervallo più piccolo e perché extra sono necessarie operazioni per correggere i calcoli per lo spostamento implicito, oggi la matematica a virgola fissa è spesso più lenta della matematica a virgola mobile.

I tipi decimali funzionano in modo molto simile ai float o ai numeri a virgola fissa, ma assumono un sistema decimale, ovvero il loro esponente (implicito o esplicito) codifica power-of-10, non power-of-2. Un numero decimale potrebbe, ad esempio, codificare una mantissa di 23456e un esponente di -2, e questo si espanderebbe a234.56. I decimali, poiché l'aritmetica non è cablata nella CPU, sono più lenti dei float, ma sono ideali per tutto ciò che comporta numeri decimali e necessita che tali numeri siano esatti, con arrotondamenti che si verificano in punti ben definiti: calcoli finanziari, quadri di valutazione, ecc. Alcuni linguaggi di programmazione hanno tipi decimali incorporati (ad es. C #), altri richiedono librerie per implementarli. Si noti che mentre i decimali possono rappresentare accuratamente frazioni decimali non ripetitive, la loro precisione non è migliore di quella dei numeri in virgola mobile; la scelta dei decimali significa semplicemente che si ottengono rappresentazioni esatte di numeri che possono essere rappresentati esattamente in un sistema decimale (proprio come i float possono rappresentare esattamente le frazioni binarie).

I numeri razionali memorizzano un numeratore e un denumeratore, in genere utilizzando una sorta di tipo intero bignum (un tipo numerico che può aumentare fino a quando i vincoli di memoria del computer lo consentono). Questo è l'unico tipo di dati fuori dal gruppo che può modellare con precisione numeri come 1/3o 3/17, così come le operazioni su di essi - razionali, a differenza degli altri tipi di dati, produrranno risultati corretti per cose come3 * 1/3. La matematica è piuttosto semplice, anche se trovare un algoritmo di factoring efficiente è piuttosto impegnativo. In alcuni linguaggi di programmazione sono incorporati tipi razionali (ad es. Common Lisp). Gli aspetti negativi di razionali includono che sono lenti (molte operazioni richiedono la riduzione delle frazioni e il factoring dei loro componenti) e che molte operazioni comuni sono difficili o impossibili da implementare e la maggior parte delle implementazioni degrada il razionale in un float quando ciò accade (ad esempio quando si chiama sin()su un razionale).

BCD (Binary Coded Decimal) utilizza "nibble" (gruppi di 4 bit) per codificare singole cifre; poiché un nibble può contenere 16 valori diversi, ma i numeri decimali richiedono solo 10, ci sono 6 valori "illegali" per nibble. Come i decimali, i numeri BCD sono decimali, cioè i calcoli eseguiti sui numeri decimali funzionano esattamente come farebbero se li avessi fatti usando carta e penna. Le regole aritmetiche per BCD sono alquanto goffe, ma il lato positivo è che convertirle in stringhe è più facile che con alcuni degli altri formati, il che è particolarmente interessante per ambienti a bassa risorsa come i sistemi embedded.

Le stringhe , sì, semplici stringhe vecchie, possono anche essere usate per rappresentare numeri frazionari. Tecnicamente, questo è molto simile al BCD, solo che esiste un punto decimale esplicito e si utilizza un byte intero per cifra decimale. Pertanto, il formato è dispendioso (vengono utilizzati solo 11 dei 256 valori possibili), ma è più semplice analizzarlo e generarlo rispetto a BCD. Inoltre, poiché tutti i valori utilizzati sono "insospettabili", innocui e neutri dalla piattaforma, i numeri codificati in stringa possono viaggiare su reti senza problemi. Non è raro scoprire che l'aritmetica viene eseguita direttamente sulle stringhe, ma è possibile e quando lo fai, sono esattamente decimali come gli altri formati decimali (decimali e BCD).


Sicuramente il punto fisso a 32 bit ha una precisione maggiore rispetto al punto mobile a 32 bit, poiché le rappresentazioni in punti fissi non includono una mantissa.
han

4
@han: dipende dalla dimensione del numero che si desidera memorizzare. I galleggianti ti forniranno (approssimativamente) la stessa precisione, non importa quanto grande o piccolo sia il numero, mentre il punto fisso ti darà la massima precisione solo se il numero che desideri memorizzare si adatta perfettamente al suo intervallo.
Leo,

@han Non necessariamente, entrambi possono comunque rappresentare 2 ^ 32 valori distinti. La quantità di informazioni trasportate è identica, indipendentemente dalla presentazione. La portata e la precisione vanno di pari passo, quindi a tale proposito l'aritmetica a virgola fissa può essere più accurata in determinate gamme. Ed evita i cattivi problemi di arrotondamento casuale, se conosci i limiti entro i quali puoi lavorare.
zxcdw,

@han: hanno la stessa precisione (o quasi). La differenza è che per i numeri a virgola fissa, la precisione (come nella dimensione di un passaggio discreto da un numero al suo successore) è costante, proprio come con gli interi, mentre con i galleggianti cresce approssimativamente in modo lineare con valore assoluto - il galleggiante il numero 1.0 ha una precisione maggiore rispetto al numero 10.000.000,0 (circa un milione di volte in più).
tdammers,

6

I numeri in virgola mobile rappresentano una vasta gamma di valori, il che è molto utile quando non si sa in anticipo quali potrebbero essere i valori, ma è un compromesso. Rappresentare 1/10 ^ 100 con un secondo numero intero non funzionerebbe.

Alcune lingue (e alcune librerie) hanno altre caratteristiche. Lisp ha tradizionalmente numeri interi di precisione infinita. Cobol ha calcoli con numeri decimali in virgola fissa.

Devi selezionare la tua rappresentazione numerica adeguata al dominio problematico.


1

Sembra che tu stia descrivendo numeri a virgola fissa .

Tenere presente che la memorizzazione della parte frazionaria di un numero in una posizione separata è esattamente identica alla creazione di un singolo spazio, il doppio del tempo, e alla memorizzazione della parte intera e frazionaria nelle due metà separate. In altre parole, è identico alla memorizzazione del numero come numero intero ma presuppone semplicemente un numero fisso di spazi decimali.

Normalmente i numeri in virgola mobile sono memorizzati usando una variazione binaria sulla notazione scientifica perché ciò che di solito conta sono cifre significative. Esistono molti altri metodi. I numeri decimali a virgola fissa vengono comunemente utilizzati, ad esempio, per memorizzare valori di valuta, dove l'accuratezza è critica fino a un certo numero intero di cifre decimali, ma il numero di cifre decimali richieste non cambia mai.


1

Si chiamerebbe BCD, penso che puoi ancora usarlo se lo desideri davvero. Tuttavia non ne vale davvero la pena in quanto:

  1. Molto raramente si verificherà un errore di arrotondamento con virgola mobile a 64 bit
  2. Rende l'aritmatico complesso e inefficiente
  3. Spreca 6 valori ogni 4 bit

La matematica BCD veniva usata molto sui primi sistemi a microprocessore a 8 bit; in effetti, su un popolare microprocessore (il 6502), l'aggiunta e la sottrazione con BCD sono altrettanto veloci per byte rispetto al binario. I videogiochi utilizzavano spesso la matematica BCD per tenere il punteggio. Non esiste una gestione speciale per il punteggio che termina a 1.000.000 di punti. Invece, aggiungendo 1 a "99 99 99" si ottiene "00 00 00" con un carry che viene ignorato. Il sovraccarico aggiuntivo per l'aggiunta di punteggi in BCD è minimo rispetto al costo di conversione di un valore binario in formato visualizzabile.
Supercat,

1

La risposta breve è che il virgola mobile è stato progettato per calcoli scientifici. Può memorizzare un numero con (fino a) un numero specificato di cifre significative, che si adatta strettamente a come viene misurata la precisione nella maggior parte dei calcoli scientifici.

Ciò tende ad essere supportato principalmente nell'hardware perché i calcoli scientifici sono stati quelli che hanno beneficiato maggiormente del supporto hardware. Ad esempio, i calcoli finanziari vengono spesso eseguiti con altri formati, ma il software finanziario di solito esegue calcoli reali abbastanza scarsi che, sebbene i formati necessari siano supportati solo nel software, le prestazioni rimangono perfettamente adeguate per la maggior parte dei software finanziari.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.