numeri a virgola mobile sono un'approssimazione, non possono memorizzare i numeri decimali esattamente. Poiché cercano di rappresentare una gamma molto ampia di numeri in soli 64 bit, devono essere approssimati in una certa misura.
È molto importante essere consapevoli di questo, perché provoca alcuni effetti collaterali strani. Ad esempio, si potrebbe ragionevolmente pensare che la somma di dieci lotti di 0.1
sia 1.0
. Anche se questo sembra logico, è anche sbagliato quando si tratta di virgola mobile:
>>> f = 0.0
>>> for _ in range (10):
... f += 0.1
...
>>> print f == 1.0
False
>>> f
0.99999999999999989
>>> str(f)
1.0
Si potrebbe pensare che n/m * m == n
. Ancora una volta, a virgola mobile mondo non è d'accordo:
>>> (1.0/103.0) * 103.0
0.99999999999999989
O forse altrettanto stranamente, si potrebbe pensare che per tutti n
, n + 1 != n
. In floating terreni punto, i numeri semplicemente non funzionano in questo modo:
>>> 10.0**200
9.9999999999999997e+199
>>> 10.0**200 == 10.0**200 + 1
True
# How much do we have to add to 10.0**200 before its
# floating point representation changes?
>>> 10.0**200 == 10.0**200 + 10.0**183
True
>>> 10.0**200 == 10.0**200 + 10.0**184
False
Vedi What every computer scientist should know about floating point numbers per un'eccellente sintesi delle questioni.
Se è necessaria la rappresentazione decimale esatta, controllare il modulo decimal, parte della libreria standard python dal 2.4. Permette di specificare il numero di cifre significative. Lo svantaggio è che è molto più lento del punto mobile, perché le operazioni in virgola mobile sono implementate nell'hardware mentre le operazioni decimali avvengono esclusivamente nel software. Ha anche i suoi problemi di imprecisione, ma se hai bisogno di una rappresentazione esatta dei numeri decimali (ad esempio per un'applicazione finanziaria) è l'ideale.
Ad esempio:
>>> 3.14
3.1400000000000001
>>> import decimal
>>> decimal.Decimal('3.14')
>>> print decimal.Decimal('3.14')
3.14
# change the precision:
>>> decimal.getcontext().prec = 6
>>> decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.142857')
>>> decimal.getcontext().prec = 28
>>> decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
+1 per chiedere una domanda intelligente, non supponendo che si trattava di un bug in Python. –
Simile a http://stackoverflow.com/questions/2880547/python-rounding-problem –
possibile duplicato di [Perché i numeri decimali non possono essere rappresentati esattamente in binario?] (Http: // stackoverflow.it/questions/1089018/why-cant-decimal-numbers-be-represented-esattamente-in-binary) –