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 23456
e 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/3
o 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).