2010-06-06 4 views
10

io sono un po 'confuso perché pitone aggiungere qualche numero decimale supplementare in questo caso di galleggiamento, per favore aiutatemi a spiegarepitone numero

>>> mylist = ["list item 1", 2, 3.14] 
>>> print mylist ['list item 1', 2, 3.1400000000000001] 
+0

+1 per chiedere una domanda intelligente, non supponendo che si trattava di un bug in Python. –

+1

Simile a http://stackoverflow.com/questions/2880547/python-rounding-problem –

+2

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) –

risposta

13

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') 
+0

>>> dall'importazione decimale * Traceback (ultimo limite): File "", riga 1, in? ImportError: nessun modulo denominato decimale c'è un errore quando provo ad importare il modulo decimale, dove posso ottenerlo? potrebbe sembrare stupido, ma io sono nuovo in Python. – user359925

+0

decimal è disponibile da Python versione 2.4 e successive. –

+2

@zhack, siamo una comunità di sviluppatori che rispondono a domande senza alcun guadagno. Smettila di dire che le tue domande sono stupide. – Warty

0

Come accennato prima, è tutto sui punti galleggiante essendo un'approssimazione.

Se volete esattezza è possibile utilizzare un numero decimale (che è una rappresentazione precisa): http://docs.python.org/library/decimal.html

a = [1.5, 1.49999] 
a 
[1.5, 1.4999899999999999] 

from decimal import Decimal 
b = [1.5, Decimal('1.4999')] 
b 
[1.5, Decimal('1.4999')] 
+0

Ricorda che molte applicazioni non finanziarie non richiedono ESECUZIONE. E funzioni come 'sin',' ln' e 'sqrt' non restituiscono risposte esatte in nessuna base. – dan04

6

Vale la pena di notare che Python 3.1 ha una nuova routine di output in virgola mobile che arrotonda questo nel modo previsto (è stato anche backport di Python 2.7):

Python 3.1 (r31:73572, Aug 15 2009, 17:12:41) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> a = [3.14] 
>>> print(a) 
[3.14] 

Dal documento What's New in Python 3.1:

Python now uses David Gay’s algorithm for finding the shortest floating point representation that doesn’t change its value. This should help mitigate some of the confusion surrounding binary floating point numbers.

The significance is easily seen with a number like 1.1 which does not have an exact equivalent in binary floating point. Since there is no exact equivalent, an expression like float('1.1') evaluates to the nearest representable value which is 0x1.199999999999ap+0 in hex or 1.100000000000000088817841970012523233890533447265625 in decimal. That nearest value was and still is used in subsequent floating point calculations.

-1

Siamo in grado di risolvere il problema da questo comando:

>>> x = 1.2 - 1.0 
>>> x 
0.19999999999999996 
>>> y = float(str(x)) 
>>> y 
0.2 

aggiungo una risposta da @ Marco