2013-08-07 10 views
14

Czy istnieje prosty i bezpośredni sposób dodawania "jednego" w numerze zmiennoprzecinkowym w Pythonie?Jak dodać plusa na końcu do liczby zmiennoprzecinkowej w Pythonie?

Znaczy to:

if a == 0.0143: 
    a = plus(a) 
    assert a == 0.0144 

def plus(a): 
    sa = str(a) 
    index = sa.find('.') 
    if index<0: 
     return a+1 
    else: 
     sb = '0'*len(sa) 
     sb[index] = '.' 
     sb[-1] = 1 
     return a+float(sb) 

To nie jest to, co chcę, bo to daje mi 0.0144000000001.

+1

To jest niesamowite pytanie. Dzięki, że pytasz. – zsong

Odpowiedz

20

Jak zauważyłeś, nie wszystkie liczby dziesiętne mogą być reprezentowane dokładnie jak pływaków:

>>> Decimal(0.1) 
Decimal('0.1000000000000000055511151231257827021181583404541015625') 
>>> Decimal(0.2) 
Decimal('0.200000000000000011102230246251565404236316680908203125') 
>>> Decimal(0.3) 
Decimal('0.299999999999999988897769753748434595763683319091796875') 
>>> Decimal(0.4) 
Decimal('0.40000000000000002220446049250313080847263336181640625') 
>>> Decimal(0.5) 
Decimal('0.5') 

Ponieważ pracujemy z właściwościami liczb po przecinku, użyj modułu decimal, który realizuje je dokładnie:

from decimal import Decimal 

def plus(n): 
    return n + Decimal('10') ** n.as_tuple().exponent 

A demo:

>>> n = Decimal('0.1239') 
>>> plus(n) 
Decimal('0.1240') 

Y Musimy reprezentować liczbę jako łańcuch, ponieważ reprezentowanie jej jako liczby zmiennoprzecinkowej straci dokładność.

Wadą jest to, że użycie Decimal spowoduje, że funkcja będzie działać około 20-30 razy wolniej niż w przypadku operacji zmiennoprzecinkowych, ale to jest koszt precyzji.

+0

+1 za rzeczywistą możliwość odczytu. Robienie tego rodzaju rzeczy jest tak łatwe do zrobienia bałaganu z kodem. – jpmc26

+0

@Blender To jest niesamowite. – zsong

+0

Zauważ, że od Pythona 3.3 moduł 'decimal' jest zaimplementowany w C i nie powinien być tak wolny, jak w przypadku floats. –

2

odpowiedź Blendera jest zdecydowanie dobra odpowiedź, ale jeśli nalegać, aby korzystać floats Wierzę, że prostym sposobem na to jest:

  1. Sprawdzaj X dla 10 ** x które mogą pomnożyć swój pływaka do liczby całkowitej.

  2. Dodaj jeden do powiększonej liczby.

  3. Podziel swój poprzedni mnożnik.

Tak to wygląda:

n = 0.125 
e = len(str(n)) - 2 
temp_n = n * 10 ** e 
temp_n += 1 
n = temp_n/10 ** e 
print n 

EDIT:

W poprzednim scenariuszu, wszystko poszło źle, gdy liczba była bardzo długa. Wyniki są obcinane przez str() i print, więc zmieniłem skrypt trochę:

n = 0.1259287345982795 
e = len(repr(n)) - 2 
temp_n = n * 10 ** e 
temp_n += 1 
n = temp_n/10 ** e 
print repr(n) 
+0

Nie działa, gdy n jest bardzo małą liczbą. 'n = 0.125928734598279', wynik to' 0.125928734599' – zsong

+0

Och, ponieważ 'str()' i 'print' obcina długi ciąg.z pomocą 'repr()' wszystko jest w porządku :) Zaktualizuję mój post. – shengy

+0

Możesz pominąć podział przez '10 ** e' i po prostu zrobić' n + 10 ** - e' – Blender

0
n = n + 1/10**(len(repr(n)) - 2) 
+0

Chcesz opracować? –

+0

Jeszcze lepiej jest 'n = n + 10 ** - (len (repr (n)) - 2)' zgodnie z sugestią @blender. Zobacz pierwszą odpowiedź @ shengy po szczegóły. Po prostu skompaktowałem i użyłem 'repr', aby to naprawić. – dansalmo

Powiązane problemy