Problem mit Countdown

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
bremer
User
Beiträge: 109
Registriert: Sonntag 25. Mai 2008, 00:13

Samstag 20. September 2008, 00:22

Code: Alles auswählen

from time import time
zaehler = int(raw_input("Geben Sie die Anzahl der Sekunden an: "))
zeitpunkt = time()
diff, grenze = 0, 0
while diff < zaehler:  # Solange die Differenz kleiner als die vorgegebene Anzahl der Sekunden ist.
    diff = time() - zeitpunkt  # diff = bisher vergangene Zeit.
    if diff >= grenze:  # Immer wenn die bisher vergangene Zeit groesser als die derzeitige Grenze ist.
        print zaehler - grenze
        grenze += 0.1
Ich bekomme als letzten Wert dann manchmal so kryptische Werte wie "1.11022302463e-16"
Kann mir jemand erklären, wie das zu Stande kommt?
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Samstag 20. September 2008, 01:25

Hmm, ich habs mal umgeschrieben, mit dem gleichen ergebniss,
würde mich auch mal interressieren, warum dabei zum schluss so ein komischer wert rauskommt, obwohl man mit gefixten werten arbeitet.

P.s so musst du nicht so viel mit differenzen und so arbeiten ;)

Code: Alles auswählen

#!/usr/bin/python
from time import sleep
import sys

spanne = int(sys.argv[1])
diff = 0.1

def countdown(spanne, diff):
    spanne -= diff
    print spanne
    return spanne

while spanne >= 0:
    sleep(diff)
    spanne = countdown(spanne, diff)
edit: ich hab das mal in ner ganz normalen while schleife probiert,
mit dem gleichen ergebniss. Scheint ein interpreter-fehler zu sein.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Samstag 20. September 2008, 07:30

Floats sind prinzipbedingt ungenau. Lebe mit den Abweichungen, benutze decimal oder rechne mit (genauen) Ganzzahlen (int) und teile dann erst das Ergebnis zur Anzeige. Das sind deine Möglichkeiten.

Das ganze liegt daran, dass Computer Zahlen im Binärsystem repräsentieren und es keine exakte Repräsentation von 0.1 gibt, wenn man nur 1/2, 1/4, 1/8, usw. als Brüche zur Verfügung hat. Steht auch im Tutorial.

Stefan
Zuletzt geändert von sma am Samstag 20. September 2008, 08:01, insgesamt 1-mal geändert.
BlackJack

Samstag 20. September 2008, 07:31

1.11022302463e-16 ist kein kryptischer Wert, sondern eine Zahl, die ganz nahe an Null dran ist. Das liegt daran, das zum Beispiel 10 mal 0.1 aufaddiert nicht 1 ist sondern:

Code: Alles auswählen

In [51]: sum([0.1] * 10)
Out[51]: 0.99999999999999989
In [52]: 1 - sum([0.1] * 10)
Out[52]: 1.1102230246251565e-16
Das wiederum ist kein Fehler von Python sondern die normale Rechenungenauigkeit mit der man bei Fliesskommazahlen in jeder Programmiersprache rechnen muss.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 20. September 2008, 07:32

nuss hat geschrieben:Scheint ein interpreter-fehler zu sein.
Sicher! :lol:

Hier wird mit Fließkommazahlen gearbeitet. Aufgrund der ganz normalen Ungenauigkeiten bei diesem Zahlentyp ist der letzte Wert nicht exakt Null, sondern nur fast Null, nämlich z.B. ca. 10^-16, das ist fast Null.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 20. September 2008, 09:34

Würde so gehen:

Code: Alles auswählen

from time import sleep
import sys

spanne = int(sys.argv[1])
diff = 0.1

def countdown(spanne, diff):
    spanne -= diff
    print round(spanne,2)
    return spanne

while spanne-diff > 0:
    sleep(diff)
    spanne = countdown(spanne, diff)
Die Bedingung bei while war auch falsch.

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 20. September 2008, 10:11

Ich hätte es so gemacht:

Code: Alles auswählen

from time import sleep

dauer = float(raw_input("Dauer: "))
while abs(dauer)>0.001:
    dauer -= 0.1
    print "%2.1f" %abs(dauer)
    sleep(0.1)
@Jens: Deine Abbruchbedingung funktioniert nicht immer korrekt. Je nachdem, ob der letzte Wert knapp über oder unter Null liegt, wird die "0.0" noch ausgegeben oder eben nicht.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Samstag 20. September 2008, 11:19

Hi

Warum nicht ganz weg von diesen Floats?

Code: Alles auswählen

from time import sleep

duration = float(raw_input("Dauer: "))
step_size = 0.1
steps = int(duration/step_size)

while steps > 0:
    print "%2.1f" % (steps*step_size)
    steps -= 1
    sleep(step_size)
Gruss
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 20. September 2008, 11:24

Dann könnte man auch von den while Schleife weg:

Code: Alles auswählen

from time import sleep

duration = float(raw_input("Dauer: "))
step_size = 0.1
steps = int(duration/step_size)

for count in xrange(steps):
    sleep(step_size)
    print count, step_size*count+step_size

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
wuf
User
Beiträge: 1481
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 20. September 2008, 13:17

Hallo Forumfreunde

Ich finde die Varianten von 'rayo' und 'jens' auch die richtigen Lösungsanstätze um das Floating-Problem in den Griff zu bekommen. (Do it with integers)

Übrigens die Variante von 'jens' müsste als 'count up' bezeichnet werden. :D

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 20. September 2008, 13:27

btw. eigentlich schade, das man nicht range(0, duration, step_size) machen kann. Da die Funktion gern integer Werte haben möchte :(

Mal selber machen:

Code: Alles auswählen

from time import sleep

def xrange2(start, stop, step=1.0):
    duration = stop - start
    steps = int(duration/step)
    for count in xrange(steps):
        yield step_size*count+step_size


duration = float(raw_input("Dauer: "))
step_size = 0.1


for no in xrange2(0, duration, step_size):
    sleep(step_size)
    print no

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten