Quando la matematica del computer non torna
Aggiunta di numeri in virgola mobile
La matematica è difficile e quando introduci i limiti fisici della memoria del computer, la matematica è più difficile.
Spesso abbiamo bisogno di fare matematica di base nel software. Un problema pratico che si pone spesso è sommare somme di denaro.
Sally ha due articoli nel carrello. Il primo articolo costa $ 12,33. Il secondo articolo costa $ 15,68. Dovremmo essere in grado di calcolare che il totale di Sally è $ 12,33 + $ 15,68 = $ 28,01. Sulla carta, questo è un problema facile da risolvere.
Tuttavia, se apro una sessione Ruby interattiva e aggiungo questi due numeri in virgola mobile, ottengo un errore di arrotondamento apparentemente folle.
I computer dovrebbero rendere i calcoli più facili, eppure qualcosa di semplice come l'addizione diventa molto poco intuitivo. Gli sviluppatori di software sanno che il comportamento non intuitivo nel codice causa bug. Quindi qual è la causa di questo errore di arrotondamento?
Rappresentare il valore
Arriveremo alla matematica, ma prima parliamo di rappresentare il valore. Abbiamo diversi modi per rappresentare il valore. Ad esempio, per rappresentare la mia età:
In inglese scritto: ventinove
Con numeri romani: XXIX
In una grotta:
Base 10: 29
La maggior parte del nostro mondo utilizza un sistema in base 10 per rappresentare i numeri, anche se ci sono alcune eccezioni interessanti . L'uso della base 10 probabilmente deriva da esseri umani che hanno 10 dita con cui contare. In un sistema in base 10, i valori sono rappresentati utilizzando 10 numeri distinti: 0,1,2,3,4,5,6,7,8,9.
Potresti ricordare che il tuo insegnante di matematica ha chiamato un numero al posto delle unità, delle decine, delle centinaia, ecc. Nota che queste sono tutte potenze di 10: 10⁰, 10¹, 10².
Potrebbe sembrare una complicazione eccessiva, ma ci aiuterà a mappare ciò che sembra ovvio sul conteggio in base 10 su altri sistemi, come il binario!
Il binario è solo un altro sistema per rappresentare il valore. Invece della base 10, usiamo la base 2. Il binario è importante per questa discussione perché i computer memorizzano i dati in memoria come binari . In binario, i numeri sono rappresentati con solo due valori: 0 e 1.
Quindi, come rappresento la mia età in binario? È rappresentato come 11101. Questa rappresentazione è semplice da derivare. Invece di valori nelle unità, nelle decine e nelle centinaia, il binario ha valori nelle unità, nelle quattro, nelle otto, ecc.: 2⁰, 2¹, 2², 2³, 2⁴.
Rappresentare valori frazionari
Proprio come con i numeri interi, anche i valori frazionari possono essere rappresentati sia in base 10 che in binario.
Per esercitarci, rappresentiamo ⅛ come decimale in entrambi i sistemi. Quando si ha a che fare con i decimali in base 10, abbiamo valori nelle posizioni dei decimi, dei centesimi e dei millesimi, ecc.
E quando si ha a che fare con i decimali in binario abbiamo la metà, il quarto e l'ottavo posto, ecc.
Decimali periodici
Posso rappresentare in modo finito qualsiasi numero intero che desidero sia in base 10 che in binario. Tuttavia, non è possibile rappresentare in modo finito tutti i valori frazionari. Ad esempio, ricorda che in base 10 la rappresentazione decimale di ⅓ si ripete all'infinito .
Allora perché non possiamo rappresentare in modo finito ⅓ in base 10?
Dal punto di vista matematico, non possiamo rappresentare ⅓ in base 10 in modo finito perché 3 non è un fattore di 10. , risulta nel tuo numero originale. La scomposizione in fattori primi di 10 = 2⋅5. Ciò significa che se il denominatore di una frazione ridotta può essere scomposto in 2 e 5, allora il valore può essere rappresentato in modo finito in base 10.
Per binario, la scomposizione in fattori primi di 2 = 2⋅1. Affinché un numero decimale sia rappresentabile in modo finito in binario, il denominatore deve essere un multiplo di 2.
Per ribadire, se il denominatore di una frazione ridotta può essere scomposto in 2 e 5, è rappresentabile finitamente in base 10. Se il denominatore di una frazione ridotta è un multiplo di 2, è rappresentabile finitamente in binario. Altrimenti, i decimali sono periodici e si ripeteranno all'infinito . Nota nella tabella sottostante che le frazioni ⅕, ¹⁄₁₀₀,³³⁄₁₀₀ e ⁶⁸⁄₁₀₀ sono rappresentabili finitamente in base 10 ma NON in binario.
Il fatto che i decimali in base 10 non siano sempre rappresentabili in modo finito in binario è il motivo per cui otteniamo errori di arrotondamento imprevisti quando sommiamo numeri in virgola mobile.
Galleggia nella memoria
I computer non hanno spazio infinito per memorizzare valori in virgola mobile. I float nella mia sessione Ruby interattiva hanno 64 bit di spazio di archiviazione.
Un numero nella rappresentazione standard binaria a virgola mobile IEEE 754 a doppia precisione a 64 bit richiede tre elementi di costruzione: segno (richiede 1 bit ed è 0 per numeri positivi o 1 per numeri negativi), esponente (11 bit), mantissa (52 bit)
Tornando ancora una volta al nostro problema iniziale di sommare somme di denaro: $ 12,33 + $ 15,68 = $ 28,01
Nel mio computer, 12.33 viene memorizzato in modo finito e impreciso come:
0–10000000010–1000101010001111010111000010100011110101110000101001
0–10000000010–1111010111000010100011110101110000101000111101011100
12.330000000000000071054273576 + 15.679999999999999715782905696 = 28.009999999999999786837179272
Per riferimento, ho utilizzato questo sito Web per eseguire le conversioni tra il formato decimale e quello a 64 bit.
Risolvere il problema
- Fai la matematica intera invece della matematica in virgola mobile (e riconverti in forma decimale quando hai finito)
- Usa librerie appositamente progettate per gestire denaro contante
- Ruby ha una classe Big Decimal nativa che "fornisce un supporto simile per numeri in virgola mobile molto grandi o molto accurati". Altre lingue hanno soluzioni simili.
Perché non otteniamo un errore di arrotondamento quando sommiamo questi due valori in virgola mobile?

![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































