Rechenoperationen mit float Zahlen (Wertebereich)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Hallo zusammen,
ich möchte eine Funktion erstellen, die float Zahlen von 0.00 bis 0.50 in Schritten von 0.05 in eine Liste gibt und die ich danach ausgeben kann. Danach möchte ich die Quadrate dieser Zahlen ebenfalls ausgeben lassen. Das Problem das ich zurzeit habe ist, das ich keinen richtigen Anfang hinbekomme, da ich mit der for - Schleife und dem range()-Befehl ja nur int-Werte hochzählen lassen kann hilft mir diese ja nicht weiter. Danach hatte ich die Idee mit einer while Schleife also: while zahl <= 0.50: , da weiß ich aber nicht wie ich dann die zahlen hochzählen lassen kann und später dann eine Berechnung damit ausführen kann. Könnt Ihr mir da etwas auf die Sprünge helfen?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@duodiscus
Vielleicht so?

Code: Alles auswählen

>>> def frange(start, stop, step, precise):
...     while start < stop:
...         yield round(start, precise)
...         start += step
... 
>>> list(frange(0.0, 0.5, 0.05, 2))
[0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5]
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@duodiscus: Also bei einer ``while``-Schleife müsstest Du doch nur in jedem Schleifendurchlauf 0.05 zu `zahl` dazu addieren. Aber Achtung: Die Genauigkeit von Gleitkommazahlen ist begrenzt und 0.05 kann der Rechner in diesem Format nicht exakt speichern:

Code: Alles auswählen

In [5]: '%.50f' % 0.05
Out[5]: '0.05000000000000000277555756156289135105907917022705'
Das heisst man kann nicht genau 0.05 addieren und damit addiert man bei jedem Schritt einen kleinen Fehler dazu und wenn man das 10 mal macht, kommt da *nicht* 0.5 heraus. Und es wird noch schräger, denn obwohl der tatsächliche Wert von 0.05 etwas *grösser* ist, wie man oben sehen kann, ist das Ergebnis von 10 mal 0.05 aufaddieren *kleiner* als 0.5:

Code: Alles auswählen

In [6]: sum(0.05 for _ in xrange(10))
Out[6]: 0.49999999999999994
Willkommen in der lustigen Welt der Gleitkommazahlen in Rechnern. :-)

Wenn man also eine ``while zahl < 0.5:``-Schleife schreibt die mit `zahl` gleich 0 anfängt und in jedem Durchlauf 0.05 dazu addiert, dann wird diese Schleife 11 mal durchlaufen. Was überraschend sein kann.

Darum addiert man nicht wiederholt in Schleifen Gleitkommawerte auf, wenn sich das vermeiden lässt. Und das lässt sich vermeiden, denn man kann ja über die ganzen Zahlen 0 bis 9 mit einer ``for``-Schleife iterieren und die entsprechende Zahl daraus berechnen. Das kann auch etwas ungenau sein, prinzipbedingt wegen den Gleitkommazahlen, aber es addieren sich so nicht die ungenauigkeiten aller vorherigen Schleifendurchläufe auf. Zum Vergleich:

Code: Alles auswählen

In [7]: zahl = 0

In [8]: zahlen = list()

In [9]: for _ in xrange(10):
   ...:     zahl += 0.05
   ...:     zahlen.append(zahl)
   ...: 

In [10]: zahlen
Out[10]: 
[0.05,
 0.1,
 0.15000000000000002,
 0.2,
 0.25,
 0.3,
 0.35,
 0.39999999999999997,
 0.44999999999999996,
 0.49999999999999994]

In [11]: [0.05 * i for i in xrange(1, 11)]
Out[11]: 
[0.05,
 0.1,
 0.15000000000000002,
 0.2,
 0.25,
 0.30000000000000004,
 0.35000000000000003,
 0.4,
 0.45,
 0.5]
Mehr zum Thema Gleitkommazahlen: http://floating-point-gui.de/
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Um mal das aufzugreifen, was BlackJack geschrieben hat:

Code: Alles auswählen

>>> def frange(start, stop, step, digits):
...     for i in xrange(int(stop/step)+1):
...         yield round(i*step, digits)
... 
>>> list(frange(0.0, 0.5, 0.05, 2))
[0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5]
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Danke für deine sehr ausführliche Antwort. Ich habe jetzt ein wenig damit rumprobiert und habe das Ergebnis nach deiner zweiten Variante in eine Liste übertragen. Der Tip mit der Fehlerquote war top. Das werde ich mir für spätere Sachen merken!

Code: Alles auswählen

def f():
   sammelstelle = [ ]

   for e in range(1,11):
       ergebnis = e*0.05
       sammelstelle.append(ergebnis)
   print(sammelstelle)       
Wenn ich das Ergebnis aber statt in eine Liste vor zu einem Tupel formen möchte. Wie muss ich das syntaktisch da schreiben? Also Ergebnis in ein Tupel und das Tupel dann der Liste zuführen!
Der .append() Befehl gibt es ja nur bei Listen und funktioniert dort leider nicht. :?

Könnte man mir da nochmal weiterhelfen?

Ich habe nämlich danach dann vor, den jeweiligen durchlauf dann zu quadrieren, das Ergebnis wiederum dann auch einem Tupel zuführen und nachher der Liste hinzufügen.

Und ganz am Ende dann die Liste ausgeben.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@duodiscus: warum der Schritt über ein Tuple? Listen sind ja dafür da, sich zu verändern, Tuple nicht.
BlackJack

@duodiscus: Ich verstehe glaube ich die Frage nicht wirklich: Du willst Tupel die genau ein Element enthalten haben? Warum? Das wäre doch nur unnötig umständlich. Wenn Du die Zahl dann quadrierst und sowohl die jeweilige Zahl als auch deren Quadrat als Tupel in einer Liste speichern möchtest, kannst Du *dann* Tupel mit den beiden Werten erstellen. Denn bei zwei Werten machen Tupel Sinn zum zusammenfassen.
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

@Sirius: Ich würde es nicht so machen. Aber in der Aufgabe die ich bearbeiten soll, ist es nunmal so vorgegeben.

@BlackJack: Nein du hast es missverstanden. Ich möchte es folgendermaßen bzw. soll es folgendermaßen aufbauen:

1. Zahlen von 0.0 bis 0.50 in 0.05er Schritten hochzählen lassen und diese Zahlen in einem Tupel ablegen.

2. Das Ergebnis dieser Zahlen zum Quadrat wiederum in ein weiteres/anderes Tupel geben.

3. Die Zahlen die hochgezählt wurden zur Basis 2 potenzieren, die Ergebnisse wiederum in ein weiteres Tupel geben.

4. Abschließend alle 3 Tupel in eine Liste geben.

5. Diese Liste dann zurückgeben.

Ich weiß jetzt nicht wie ich diese verschiedenen Tupel erstellen kann. Elemente einer Liste hinzufügen ist klar, aber wie die Ergebnisse in ein Tupel verwandeln?
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

@duodiscus:

Code: Alles auswählen

l = range(10)
type(l)
#<type 'list'>
t = tuple(l)
type(t)
#<type 'tuple'>
als kleiner Hinweis ;-)
BlackJack

Wobei das IMHO sinnfrei ist beziehungsweise sogar eine falsche Verwendung von Tupeln. Tupel verwendet man eher für Daten mit unterschiedlicher Bedeutung um die zu einem Objekt zusammen zu fassen. Also zum Beispiel Koordinaten oder einen Eintrag in einer Highscoreliste mit Punktanzahl und Name als Elemente. Das was Du da hast sind ja Daten wo jedes Element die gleiche Bedeutung hat — eine Zahl in der Sequenz.
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Aber die Aufgabe wurde mir eben so gestellt. :roll:
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

@mcdwerner:
Danke ;)
Er gibt mir aber bei mir eine Fehlermeldung:

Code: Alles auswählen

for e in range(1,11):
       a = e*0.05
       ergebnis1 = tuple(a)
   print(type(ergebnis1))

Code: Alles auswählen

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    f5()
  File "/Users/A11.py", line 6, in f5
    ergebnis1 = tuple(a)
TypeError: 'float' object is not iterable
BlackJack

@duodiscus: Ja, man kann ja auch eine Zahl nicht in ein Tupel umwandeln. Genau was die Fehlermeldung sagt. Du musst an `tuple()` ein Objekt übergeben über das man iterieren kann. Also zum Beispiel eine Liste mit den Zahlen. Also erst eine Liste mit den Zahlen erstellen und *die* danach in ein Tupel überführen.

Das ist einer der Gründe warum Tupel für so etwas blöd sind: Man muss schon ein anderes Objekt haben, das alle Elemente liefert um daraus ein Tupel zu erstellen, denn Tupel können nach dem Erstellen nicht mehr verändert werden.

Edit: Wenn man nicht gerade Anfänger ist, würde man einen Generatorausdruck als Argument verwenden, das hält den Quelltext halbwegs erträglich und man erzeugt keine extra Liste. Zumindest nicht explizit, und intern kann die `tuple()`-Funktion das besser optimieren als man das mit einer Liste auf Python-Ebene selber tun könnte:

Code: Alles auswählen

In [4]: tuple(i * 0.5 for i in xrange(1, 11))
Out[4]: (0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0)
duodiscus
User
Beiträge: 97
Registriert: Sonntag 6. April 2014, 16:10

Habe jetzt eine Lösung. Mit der Umwandlung von Liste in Tupel. Und dann nachher wieder zurück. Gibt sicher noch andere Varianten, da diese Methode doch recht kompliziert ist. Aber sie funktioniert so...
Heini
User
Beiträge: 21
Registriert: Donnerstag 12. April 2007, 10:48

Ich nehme mal an du darfst kein numpy verwenden, oder? (Andernfalls fehlt bei der Aufgabe der pädagogische Effekt, nehme ich an.)

Code: Alles auswählen

import numpy

a=numpy.arange(0,51,5)/100.
b=tuple(a)
c=tuple(a**2)

print type(b), b
print type(c), c
BlackJack

Wobei ich bei Numpy wohl ``linspace(0, 0.5, 11)`` für `a` verwendet hätte. :-)
Antworten