Błędne sumowanie

Odpowiedz Nowy wątek
2017-05-19 14:01
yazor
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?

edytowany 2x, ostatnio: furious programming, 2017-05-21 12:22
hehe, kiedyś mialem taki problem na apce androida ktora robilem na prace dyplomowa, nie mialem czasu naprawiac. Program miedzy innymi zliczal ceny, to dobralem na prezentacje takie ceny zeby dobrze dodawalo;p. Poza tym to nie problem tylko Pythona ale i Javy. Sam jestem ciekawy odp. Temat dawno przeze mnie zapomniany - rafallvlup 2017-05-19 14:08

Pozostało 580 znaków

2017-05-19 14:16
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.

Pozostało 580 znaków

2017-05-19 14:21
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ś:)

Pozostało 580 znaków

2017-05-19 14:32
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.

Pozostało 580 znaków

2017-05-19 14:37
yazor
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

edytowany 1x, ostatnio: bogdans, 2017-05-20 09:26
Wrzucaj kod w odpowiednie znaczniki, łatwiej się czyta. - atmal 2017-05-19 14:38
W Pythonie też liczą się wcięcia. Bez znaczników kod nie ma wcięć - przestaje działać. - Spine 2017-05-19 14:42
Były takie problemy i w pascalu, tylko po prostu nie wyświetlałeś liczb do pewnej dokładności. - krzysiek050 2017-05-19 14:50

Pozostało 580 znaków

2017-05-19 14:47
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.

edytowany 2x, ostatnio: Spine, 2017-05-19 14:50

Pozostało 580 znaków

2017-05-19 14:50
yazor
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

Pozostało 580 znaków

2017-05-19 14:51
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.

edytowany 3x, ostatnio: Spine, 2017-05-19 14:54
Jest też inna ciekawostka, w Pythonie 3.6 w ogóle nie ma typu long. Już typ int jest "nieskończony". - bogdans 2017-05-19 20:08
Nieźle ;) Upraszczają składnię gdzie się da ;) - Spine 2017-05-19 20:25

Pozostało 580 znaków

2017-05-20 17:34
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()

Linux Mint
Arduino / Python 3.5.2

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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