Cosa causa errori di arrotondamento in virgola mobile?


62

Sono consapevole che l'aritmetica in virgola mobile presenta problemi di precisione. Di solito li supero passando a una rappresentazione decimale fissa del numero o semplicemente trascurando l'errore.

Tuttavia, non so quali sono le cause di questa inesattezza. Perché ci sono così tanti problemi di arrotondamento con i numeri float?


28
Per essere precisi, non è proprio l' errore causato dall'arrotondamento di cui la maggior parte delle persone si preoccupa - è il fatto che l'arrotondamento binario in virgola mobile si comporta in modo non intuitivo. Il passaggio a una rappresentazione decimale può fare si comportano arrotondamento in un modo più intuitivo, ma in cambio si quasi sempre aumentare l'errore relativo (oppure essere necessario aumentare lo spazio di archiviazione per compensare).
Daniel Pryden,

12
Il mio tentativo di chiarire le confusioni più comuni: floating-point-gui.de
Michael Borgwardt

penso che il significato di @DanielPryden sia "Il passaggio a una rappresentazione [a virgola fissa] può comportare un arrotondamento in un modo più intuitivo ..." . ciò che causa problemi di arrotondamento, sia che si tratti di numeri fissi o in virgola mobile, è la larghezza delle parole finite di entrambi. è solo che, con il virgola mobile, l'entità dell'errore di arrotondamento normalmente rimane approssimativamente proporzionale all'entità del numero da arrotondare. (tranne quando si diventa veramente piccoli e per "denormalizzare" i numeri.)
robert bristow-johnson

@robert: non è esattamente quello a cui mi riferivo. L '"errore" che molte persone incontrano in virgola mobile non ha nulla a che fare con il virgola mobile in sé, è la base. IEEE-754 galleggia e raddoppia usa un esponente nella base 2, il che significa che i numeri frazionari si arrotondano a poteri negativi di due (1/2, 1/16, 1/1024, ecc.) Anziché a poteri negativi di 10 (1 / 10, 1/1000, ecc.) Ciò porta a risultati non intuitivi come arrotondamento da 0,1 a 0,1000001 e problemi simili.
Daniel Pryden,

Puoi fare numeri in virgola mobile in base 10: è così che funziona il decimaltipo di .NET . Il punto fisso, d'altra parte, è diverso. Finché l'intervallo è limitato, il punto fisso è una buona risposta. Ma l'intervallo restrittivo rende il punto fisso non adatto a molte applicazioni matematiche e, di conseguenza, le implementazioni dei numeri a punto fisso spesso non sono ottimizzate nell'hardware.
Daniel Pryden,

Risposte:


82

Questo perché alcune frazioni hanno bisogno di una quantità molto grande (o addirittura infinita) di luoghi per essere espressi senza arrotondamento. Questo vale per la notazione decimale tanto quanto per i binari o qualsiasi altro. Se dovessi limitare la quantità di posizioni decimali da utilizzare per i tuoi calcoli (ed evitare di fare calcoli nella notazione della frazione), dovresti arrotondare anche un'espressione semplice come 1/3 + 1/3. Invece di scrivere 2/3 come risultato dovresti scrivere 0.33333 + 0.33333 = 0.66666 che non è identico a 2/3.

Nel caso di un computer, il numero di cifre è limitato dalla natura tecnica della sua memoria e dei registri della CPU. La notazione binaria utilizzata internamente aggiunge alcune ulteriori difficoltà. I computer normalmente non possono esprimere numeri in notazione frazionaria, sebbene alcuni linguaggi di programmazione aggiungano questa capacità, che consente di evitare tali problemi in una certa misura.

Ciò che ogni scienziato informatico dovrebbe sapere sull'aritmetica a virgola mobile


12
Spot on. Vorrei anche notare che alcuni numeri che terminano in decimale non terminano in binario. In particolare 0,1 è un numero ricorrente in binario e quindi nessun numero binario in virgola mobile può rappresentare esattamente 0,1.
Jack Aidley

4
I punti mobili non sono utili solo per molti decimali. Gli interi a 32 bit possono contare solo fino a circa 4 miliardi, ma un float a 32 bit può essere quasi infinitamente grande.
Abhi Beckert,

7
In particolare, le frazioni che possiamo esprimere come decimali finiti sono quelle la cui fattorizzazione in base al denominatore contiene solo 2 e 5 (ad esempio, possiamo esprimere 3/10 e 7/25, ma non l'11 / 18). Quando passiamo al binario, perdiamo il fattore 5, in modo che solo le razionali diadiche (ad esempio 1/4, 3/128) possano essere espresse esattamente.
David Zhang,

70

In primo luogo, gli errori di arrotondamento derivano dal fatto che l' infinità di tutti i numeri reali non può essere rappresentata dalla memoria finita di un computer , per non parlare di una piccola porzione di memoria come una singola variabile in virgola mobile , quindi molti numeri memorizzati sono solo approssimazioni di il numero che devono rappresentare.

Poiché esiste solo un numero limitato di valori che non sono un'approssimazione e qualsiasi operazione tra un'approssimazione e un altro numero risulta in un'approssimazione, gli errori di arrotondamento sono quasi inevitabili .

L'importante è capire quando è probabile che causino un problema e adottare misure per mitigare i rischi .


Oltre all'essenziale Cosa deve sapere ogni scienziato informatico sull'aritmetica in virgola mobile di David Goldberg (ripubblicato da Sun / Oracle come appendice alla loro Guida al calcolo numerico ), menzionato da Thorsten , il giornale ACCU Overload ha fatto un eccellente serie di articoli di Richard Harris sui Floating Point Blues .

La serie è iniziata con

Il calcolo numerico presenta molte insidie. Richard Harris inizia a cercare un proiettile d'argento.

Il drago dell'errore numerico non viene spesso risvegliato dal suo sonno, ma se affrontato con noncuranza, occasionalmente infliggerà danni catastrofici ai calcoli del programmatore inconsapevole.

Tanto che alcuni programmatori, dopo averlo investito nelle foreste dell'aritmetica in virgola mobile IEEE 754, sconsigliano ai loro compagni di viaggiare in quella terra giusta.

In questa serie di articoli esploreremo il mondo dell'informatica numerica, contrastando l'aritmetica in virgola mobile con alcune delle tecniche che sono state proposte come sostituzioni più sicure per esso. Impareremo che il territorio del drago è davvero di vasta portata e che in generale dobbiamo camminare con cautela se temiamo la sua devastante attenzione.

Richard inizia spiegando la tassonomia dei numeri reali, razionale, irrazionale, algebrica e trascendentale. Successivamente, spiega la rappresentazione IEEE754, prima di passare all'errore di annullamento e all'ordine dei problemi di esecuzione.

Se non leggi più in profondità di questo, avrai un'eccellente messa a terra dei problemi associati ai numeri in virgola mobile.

Se vuoi saperne di più, tuttavia, continua con

Quindi passa a cercare di aiutarti a curare il tuo Calculus Blues

e ultimo ma non meno importante, c'è

L'intera serie di articoli merita di essere esaminata, e con 66 pagine in totale, sono ancora più piccole delle 77 pagine del documento Goldberg .

Mentre questa serie copre gran parte dello stesso terreno, l'ho trovata piuttosto più accessibile del documento di Goldberg . Ho anche trovato più facile capire le parti più complesse del documento dopo aver letto i precedenti articoli di Richards e dopo quei primi articoli, Richard si dirama in molte aree interessanti non toccate dal documento di Goldberg.


Come detto ak menzionato nei commenti:

Come autore di quegli articoli, vorrei menzionare che ho creato versioni interattive di essi sul mio blog www.thusspakeak.com a partire da thusspakeak.com/ak/2013/06 .


1
Come autore di quegli articoli, vorrei menzionare che ho creato versioni interattive di essi sul mio blog www.thusspakeak.com a partire da thusspakeak.com/ak/2013/06 .
così parlava il

Grazie @ thusspakea.k. Ho aggiunto una nota alla mia risposta e quegli elementi interattivi funzionano molto bene.
Mark Booth,

12

Bene, Thorsten ha il collegamento definitivo . Aggiungerei:

Qualsiasi forma di rappresentazione avrà un errore di arrotondamento per un certo numero. Prova a esprimere 1/3 in virgola mobile IEEE o in decimale. Né può farlo con precisione. Questo va oltre la risposta alla tua domanda, ma ho usato con successo questa regola empirica:

  • Memorizza i valori immessi dall'utente in decimale (perché quasi sicuramente li hanno immessi in una rappresentazione decimale - pochissimi utenti useranno binario o esadecimale). In questo modo hai sempre l'esatta rappresentazione immessa dall'utente.
  • Se è necessario memorizzare le frazioni immesse dall'utente, memorizzare il numeratore e il denominatore (anche in decimali)
  • Se si dispone di un sistema con più unità di misura per la stessa quantità (come Celsius / Fahrenheit) e l'utente può immettere entrambi, memorizzare il valore immesso e le unità in cui sono stati inseriti. Non tentare di convertire e salvare come una singola rappresentazione, a meno che non sia possibile farlo senza perdita di precisione / accuratezza. Utilizzare il valore e le unità memorizzati in tutti i calcoli.
  • Memorizza i valori generati dalla macchina in virgola mobile IEEE (possono essere numeri generati da un dispositivo di misurazione elettronico, come un sensore analogico con un convertitore A / D, o il risultato non arrotondato di un calcolo). Nota che questo non si applica se stai leggendo un sensore su una connessione seriale e ti sta già dando il valore in un formato decimale (es. 18.2 C).
  • Memorizza i totali visualizzabili dall'utente, ecc., In decimale (come il saldo di un conto bancario). Arrotonda in modo appropriato, ma usa quel valore come valore definitivo per tutti i calcoli futuri.

Vorrei aggiungere: prendere in considerazione l'utilizzo di un pacchetto matematico di precisione arbitraria come ARPREC o decNumber.
Blrfl,

Non decimale (al contrario di binario) ha molti vantaggi per i valori interi, come il numeratore e il denominatore di una frazione. Entrambi possono memorizzare valori interi esatti e il binario è più efficiente. C'è un certo costo nella conversione avanti e indietro per input e output, ma è probabile che sia sommerso dal costo di eseguire fisicamente l'I / O.
Keith Thompson,

10

Ciò che sembra non essere stato menzionato finora sono i concetti di un algoritmo instabile e un problema mal condizionato . Mi rivolgerò per primo al primo, poiché sembra essere una trappola più frequente per i numerici novizi.

Considera il calcolo dei poteri del rapporto reciproco aureo φ=0.61803…; un modo possibile per farlo è usare la formula di ricorsione φ^n=φ^(n-2)-φ^(n-1), iniziando con φ^0=1e φ^1=φ. Se esegui questa ricorsione nel tuo ambiente informatico preferito e confronti i risultati con potenze accuratamente valutate, troverai una lenta erosione di cifre significative. Ecco cosa succede ad esempio in Mathematica :

ph = N[1/GoldenRatio];  
Nest[Append[#1, #1[[-2]] - #1[[-1]]] & , {1, ph}, 50] - ph^Range[0, 51]  
{0., 0., 1.1102230246251565*^-16, -5.551115123125783*^-17, 2.220446049250313*^-16, 
-2.3592239273284576*^-16, 4.85722573273506*^-16, -7.147060721024445*^-16, 
1.2073675392798577*^-15, -1.916869440954372*^-15, 3.1259717037102064*^-15, 
-5.0411064211886014*^-15, 8.16837916750579*^-15, -1.3209051907825398*^-14, 
2.1377864756200182*^-14, -3.458669982359108*^-14, 5.596472721011714*^-14, 
-9.055131861349097*^-14, 1.465160458236081*^-13, -2.370673237795176*^-13, 
3.835834102607072*^-13, -6.206507137114341*^-13, 1.004234127360273*^-12, 
-1.6248848342954435*^-12, 2.6291189633497825*^-12, -4.254003796798193*^-12, 
6.883122762265558*^-12, -1.1137126558640235*^-11, 1.8020249321541067*^-11, 
-2.9157375879969544*^-11, 4.717762520172237*^-11, -7.633500108148015*^-11, 
1.23512626283229*^-10, -1.9984762736468268*^-10, 3.233602536479646*^-10, 
-5.232078810126407*^-10, 8.465681346606119*^-10, -1.3697760156732426*^-9, 
2.216344150333856*^-9, -3.5861201660070964*^-9, 5.802464316340953*^-9, 
-9.388584482348049*^-9, 1.5191048798689004*^-8, -2.457963328103705*^-8, 
3.9770682079726053*^-8, -6.43503153607631*^-8, 1.0412099744048916*^-7, 
-1.6847131280125227*^-7, 2.725923102417414*^-7, -4.4106362304299367*^-7, 
7.136559332847351*^-7, -1.1547195563277288*^-6}

Il risultato presunto per φ^41ha il segno sbagliato e, ancor prima, i valori calcolati ed effettivi per φ^39condividere nessuna cifra in comune ( 3.484899258054952* ^ - 9 for the computed version against the true value7.071019424062048 *^-9). L'algoritmo è quindi instabile e non si dovrebbe usare questa formula di ricorsione in aritmetica inesatta. Ciò è dovuto alla natura intrinseca della formula di ricorsione: esiste una soluzione "in decomposizione" e "crescente" a questa ricorsione, e provare a calcolare la soluzione "in decomposizione" con una soluzione diretta quando esiste una soluzione "crescente" alternativa per dolore numerico. Si dovrebbe quindi garantire che i suoi algoritmi numerici siano stabili.

Ora, sul concetto di un problema mal condizionato : anche se potrebbe esserci un modo stabile per fare qualcosa numericamente, potrebbe benissimo essere che il problema che hai non può essere risolto dal tuo algoritmo. Questo è colpa del problema stesso e non del metodo di soluzione. L'esempio canonico in termini numerici è la soluzione di equazioni lineari che coinvolgono la cosiddetta "matrice di Hilbert":

Matrice di Hilbert

La matrice è l'esempio canonico di una matrice mal condizionata : il tentativo di risolvere un sistema con una matrice di Hilbert di grandi dimensioni potrebbe restituire una soluzione imprecisa.

Ecco una dimostrazione di Mathematica : confronta i risultati dell'aritmetica esatta

Table[LinearSolve[HilbertMatrix[n], HilbertMatrix[n].ConstantArray[1, n]], {n, 2, 12}]
{{1, 1}, {1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 
  1}, {1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1,
   1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 
  1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}

e inesatta aritmetica

Table[LinearSolve[N[HilbertMatrix[n]], N[HilbertMatrix[n].ConstantArray[1, n]]], {n, 2, 12}]
{{1., 1.}, {1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1., 1.},  
  {1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1.}, 
  {1., 1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1., 1., 1.},  
  {1., 1., 1., 0.99997, 1.00014, 0.999618, 1.00062, 0.9994, 1.00031, 
  0.999931}, {1., 1., 0.999995, 1.00006, 0.999658, 1.00122, 0.997327, 
  1.00367, 0.996932, 1.00143, 0.999717}, {1., 1., 0.999986, 1.00022, 
  0.998241, 1.00831, 0.975462, 1.0466, 0.94311, 1.04312, 0.981529, 
  1.00342}}

(Se l'hai provato a Mathematica , noterai alcuni messaggi di errore che avvertono del mal condizionamento che appare.)

In entrambi i casi, semplicemente aumentare la precisione non è una cura; ritarderà solo l'inevitabile erosione delle figure.

Questo è ciò che potresti dover affrontare. Le soluzioni potrebbero essere difficili: per la prima volta, o si torna al tavolo da disegno o si guadagna diari / libri / qualunque cosa per scoprire se qualcun altro ha trovato una soluzione migliore di te; per il secondo, o ti arrendi o riformuli il tuo problema in qualcosa di più trattabile.


Vi lascio con una citazione di Dianne O'Leary:

La vita può darci alcuni problemi mal condizionati, ma non c'è motivo di accontentarsi di un algoritmo instabile.


9

perché i numeri decimali in base 10 non possono essere espressi in base 2

o in altre parole 1/10 non può essere trasformato in una frazione con una potenza di 2 nel denominatore (che è essenzialmente ciò che sono i numeri in virgola mobile)


11
Non esattamente vero: 0,5 e 0,25 possono essere espressi nella base 2. Penso che intendi "non tutti i numeri decimali della base 10".
Scott Whitlock,

3
Più accuratamente. Non tutti i numeri frazionari possono essere rappresentati esattamente usando una notazione a virgola mobile (cioè con. Sia la base 2 che la base 10 hanno questo esatto problema). Prova a farlo 9*3.3333333in decimale e compara a9*3 1/3
Martin York il

1
Questa è la fonte più comune di confusione in virgola mobile. .1 + .1 != .2perché viene utilizzata la codifica binaria a virgola mobile, non decimale.
Sean McMillan,

@SeanMcMillan: E 1.0/3.0*3.0 != 1.0, poiché viene utilizzata la codifica binaria in virgola mobile, non trinaria.
Keith Thompson

8

In matematica, ci sono infiniti numeri razionali. Una variabile a 32 bit può avere solo 2 32 valori diversi e una variabile a 64 bit solo 2 64 valori. Pertanto, ci sono infiniti numeri razionali che non hanno una rappresentazione precisa.

Potremmo elaborare schemi che ci consentano di rappresentare perfettamente 1/3 o 1/100. Si scopre che per molti scopi pratici questo non è molto utile. C'è una grande eccezione: in finanza, le frazioni decimali spesso compaiono. Ciò è dovuto principalmente al fatto che la finanza è essenzialmente un'attività umana, non fisica.

Pertanto, di solito scegliamo di usare il virgola mobile binario e arrotondare qualsiasi valore che non può essere rappresentato in binario. Ma in finanza, a volte scegliamo il virgola mobile decimale e arrotondiamo i valori al valore decimale più vicino.


2
Ancora peggio, mentre una quantità infinita (infinitamente infinita) di memoria consentirebbe di rappresentare tutti i razionali, non sarebbe sufficiente per rappresentare i reali. Ancora peggio, quasi tutti i numeri reali non sono numeri calcolabili. Il meglio che possiamo fare con una quantità finita di memoria è approssimare un sottoinsieme di intervalli finiti dei reali.
David Hammen,

4
@Kevin: Stai parlando dei numeri calcolabili, che è un piccolo sottoinsieme (un sottoinsieme con misura zero) dei reali.
David Hammen,

1
+1 per la spiegazione più elementare: stai cercando di rappresentare una quantità infinita di numeri con un numero finito di bit.
Raku,

1
@DavidHammen: i numeri calcolabili sono un piccolo sottoinsieme (di misura zero) dei reali - ma ogni numero con cui lavorerai mai in un programma è, per definizione, calcolabile.
Keith Thompson,

3
@Giorgio: se si sceglie la rappresentazione corretta, la radice quadrata di 2 è rappresentabile, ad esempio, come stringa "√2". (Il mio vecchio calcolatore HP-48 è stato in grado di fare esattamente questo, e la quadratura di quel valore ha prodotto esattamente 2.0.) Esiste solo un'infinità numerabile di numeri reali rappresentabili per qualsiasi rappresentazione finita - ma nessun calcolo può produrre un numero che non lo è, in linea di principio, rappresentabile. In pratica, il virgola mobile binario limita drasticamente l'insieme dei numeri rappresentabili, con il vantaggio della velocità ardente e della minuscola memoria relativa alle rappresentazioni simboliche.
Keith Thompson

-2

l'unico "ovvio problema di arrotondamento" con numeri a virgola mobile a cui penso è con i filtri a media mobile:

$$ \ begin {align} y [n] & = \ frac {1} {N} \ sum \ limits_ {i = 0} ^ {N-1} x [ni] \ & = y [n-1] + \ frac {1} {N} (x [n] - x [nN]) \ \ end {align} $$

per far funzionare tutto questo senza l'accumulo di rumore, devi assicurarti che $ x [n] $ che aggiungi negli esempi attuali sia esattamente uguale a $ x [nN] $ che sottrarrai $ N $ campioni nel futuro. in caso contrario, ciò che è diverso è un po 'di turd che si blocca nella linea di ritardo e non uscirà mai. questo perché questo filtro a media mobile è in realtà costruito con un IIR che ha un polo marginalmente stabile a $ z = 1 $ e uno zero che lo annulla all'interno. ma è un integratore e qualsiasi schifezza che viene integrata e non completamente rimossa esisterà per sempre nella somma degli integratori. questo è dove il punto fisso non ha lo stesso problema dei numeri in virgola mobile.


ehi, il markup matematico $ LaTeX $ non funziona nel forum prog.SE ??? è davvero zoppo se non lo fa.
robert bristow-johnson il

1
Vedi questo su meta.SO e domande collegate
AakashM
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.