Błędne sumowanie

0

Witam

Próbowałem sprawdzić Pythona, ale już na takim prostym programie otrzymuję dziwny wynik (używam PyCharm)

Otóż program:

licznik = 0.0
while True:
    print (licznik)
    licznik += 0.4
    if licznik >= 5:
        break
print()

wyświetla następujące wartości:

0.0
0.4
0.8
1.2000000000000002
1.6
2.0
2.4
2.8
3.1999999999999997
3.5999999999999996
3.9999999999999996
4.3999999999999995
4.8

Dlaczego pojawiają się takie dziwne wartości. Rozumiem przy dzieleniu gdy pojawiają się wartości rzeczywiste, ale tu jest zwykłe dodawanie. Dlaczego zamiast 1.2 pojawia się takie dziwne zaokrąglenie?

2

Nie ważne czy przy dzieleniu, mnożeniu, dodawaniu czy odejmowaniu, tak będzie zawsze bo nie można przedstawić, na przykład, 1.2 za pomocą float, dlatego dostajesz wynik bardzo bliski do tego co chciałeś.

Użyj decimal.

A tu więcej o problemie klik!, gdzie problem porównywany jest do przedstawiania 1/3 używając systemu dziesiątkowego.

0

A zobacz przy warunku zamiast 5 wpisac 5.0
Może program glupieje, bo to inne typu danych, licznik float, a w warunku int (jeśli mnie dobrze zrozumiałeś:)

0

Nie głupieje. Jest to normalne zachowanie jeżeli nie używasz zmiennej typu podwójnej precyzji. O problemie wyżej.
Dodam, że występuje to nie tylko w Pythonie ale i wielu innych językach i jest to jak najbardziej normalne.

0

Zmieniłem na if licznik >= 5.0: ale też bez zmian.

Zmodyfikowałem zapis sumowania na
icznik = licznik + 0.4

ale też otrzymuję dziwne wyniki.

Spróbowałem stworzyć bardziej prosty program:

wynik = 0.0
licznik = 0.8
wynik = licznik + 0.4
print (wynik)

i otrzymuję 1.2000000000000002

Pracowałem wcześniej na Pascalu i takich problemów nie było

0

Tak jak już radzono, użyj decimal, jeśli chcesz dokładne liczby zmiennoprzecinkowe:

from decimal import Decimal

licznik = Decimal(0)
while True:
	print (licznik)
	licznik += Decimal('0.4')
	if licznik >= Decimal(5):
		break
print()

Po prostu typ float ma skończoną dokładność (chociaż w Pythonie float jest interpretowany jako double, to wciąż za mało jak widać). Dzięki temu obliczenia są szybkie i nadają się do gier. Jeśli chcesz mieć dokładne ułamki, to musisz skorzystać z wolniejszych metod.

0

OK. Dzięki serdeczne za pomoc. Trochę to dziwne, ale skoro tak ma być...
Trzeba będzie bawić się z decimal. Jeszcze raz dzięki

0

Jest jeszcze fajny typ fraction, który pozwala Ci operować na ułamkach zwykłych ;) - https://docs.python.org/2/library/fractions.html

No i ciekawostka. W Pythonie typ long nie ma normalnych ograniczeń. Można w niego ładować liczby większe niż long np. w C.

0

Polecam dopóki to możliwe operowanie na liczbach całkowitych, pomimo większej ilości kalkulacji będzie to metoda szybsza i zdecydowanie bardziej dokładna.
Poza tym, nie wiem czy nie będzie lepiej operować na przybliżeniu round zamiast używać Decimal'a. Dodatkowym elementem jest możliwy błąd w obliczeniach procka, na przykład przy prockach intela często występujący (z tego co słyszałem, sam korzystam i przeciwskazań nie mam ;P).
Przy okazji ciekawostka dzielenie przez potęgi dwójki są dobrze zoptymalizowane w pythonie przez przesunięcie bitowe napisane w bibliotece C jeśli mnie pamięć nie myli ;p.
Nie wiem jak to z dziesiątką, ale też jest krótsze znacznie od dzielenia na przykład przez 7, co optymalizuje operacje na liczbach zmiennoprzecinkowych przy odpowiednim przekładzie na spotęgowane dziesiątki :D.

Przykład programu na całkowitych który powinien rozwiązać twój problem:


for licznik in range(0, 50, 4):
    print (licznik/10)
print()

1 użytkowników online, w tym zalogowanych: 0, gości: 1