Ganzzahlige Teilung von Float-Objekten

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.
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Donnerstag 15. Mai 2008, 09:31

Ich speichere ganze Zahlen zwischen -2**15 und 2**15 in Python-Float-Objekten,
und fuehre nur Teilungen aus, wenn diese auch mathematisch aufgehen.
Kann bei einer solchen Division ein Rungdungsfehler auftreten,
ist das compiler-abhaengig, oder ist das ganz unmoeglich?

Beispiel:

Code: Alles auswählen

a = float(169)
b = float(13)
assert 1000000*(a/b) == 13000000
Muss a/b immer genau 13 sein, oder koennte a/b==12.9999999999999 vorkommen?
Zuletzt geändert von Goswin am Donnerstag 15. Mai 2008, 10:11, insgesamt 1-mal geändert.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Donnerstag 15. Mai 2008, 09:45

Ich habe ein Verständnisproblem: 2**-15 ist doch keine ganzzahliges Objekt? Und wenn mit Du float-Objekten mit Nachkommaanteil rechnest kann es immer zu Rundungsfehlern kommen. Das ist weniger vom Compiler abhängig mit dem Python auf Deiner Maschine kompiliert wurde, sondern eher von Deiner Maschine selbst (wir gehen mal davon aus, daß der Compiler "gescheit" angepasst war). siehe http://docs.python.org/tut/node16.html

Gruß,
Christian
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Donnerstag 15. Mai 2008, 10:03

Vlt. ist -2**15 gemeint. Warum arbeitest du nicht mit Integern?
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Donnerstag 15. Mai 2008, 10:26

Das mit dem 2**-15 anstelle von -2**15 war ein Tippfehler; tut mir leid.

Ich arbeite mit Float-Objekten, um bei ungünstiger Eingabe ein Overflow zu vermeiden. 90% oder mehr meiner Anwendungsfälle erzeugen Zahlen, die zwischen -2**15 und 2**15 liegen, und in allen diesen Fällen (mit immerhin Millionen von Rechnungen) möchte ich Rundungsfehler vermeiden. Im restlichen 10% der Fälle würde bei einer Integer-Speicherung ein Overflow entstehen, und dort wäre bei Float-Objekten ein Rundungsfehler letztlich unvermeidbar (Long-Integer-Objekte kommen bei Millionen von Rechnungen sowieso nicht in Frage, das wird echt langsam). Und wenn ich jedesmal explizit nachfrage, ob die Zahlen auch klein genug sind, dann ist der Code entschieden nicht mehr benutzerfreundlich.
BlackJack

Donnerstag 15. Mai 2008, 11:33

Die Erklärung habe ich nicht so ganz verstanden!? Wenn nur ein paar von den Zahlen grösser als der Wertebereich von `int` sind, müssen doch auch nur *diese* Zahlen als `long` repräsentiert werden!? Der grosse Rest kann als `int` gespeichert werden.

Ansonsten sind `float` bei grossen Zahlen ungenau, weil die niederwertigen Stellen der originalen Zahl einfach als 0 angenommen werden, wenn nicht mehr alles in die Mantisse passt.
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Donnerstag 15. Mai 2008, 11:37

Hast du schon mal ausprobiert, ob die Integer-Geschwindigkeit ausreicht? Am Ende auf Floats umstellen wäre eine recht einfache Aufgabe.

Bedingt durch die Rechnerarchitektur lassen sich Rundungsfehler bei Floats natürlich nicht vermeiden. Es kommt eben auf die Genauigkeit an, die du brauchst.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Donnerstag 15. Mai 2008, 11:48

Wäre eine eigene Integer-Klasse evtl schneller?

Code: Alles auswählen

class MyLong:
    def __init__(self, mant, exp):
        self.mant = mant
        self.exp = exp
    def __div__(self, other):
        return MyLong(self.mant/other.mant, self.exp-other.exp)
    def __str__(self):
        return "%de%d" % (self.mant, self.exp)
    def __repr__(self):
        return str(self)
BlackJack

Donnerstag 15. Mai 2008, 11:57

Etwas mit Mantisse und Exponent ist keine Ganzzahl sondern eine Fliesskommazahl. Und das selbst in Python zu implementieren ist sicher langsamer als die Implementierung in der Prozessorhardware.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Donnerstag 15. Mai 2008, 12:00

BlackJack hat geschrieben:Etwas mit Mantisse und Exponent ist keine Ganzzahl sondern eine Fliesskommazahl. Und das selbst in Python zu implementieren ist sicher langsamer als die Implementierung in der Prozessorhardware.
long/long ist aber bestimmt nicht in Prozessorhardware gegossen.

Abgesehen davon, dass meine Klasse von verbuggt ist, hätte ich keine Rundungsfehler.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 15. Mai 2008, 12:17

Darii hat geschrieben:
BlackJack hat geschrieben:Etwas mit Mantisse und Exponent ist keine Ganzzahl sondern eine Fliesskommazahl. Und das selbst in Python zu implementieren ist sicher langsamer als die Implementierung in der Prozessorhardware.
long/long ist aber bestimmt nicht in Prozessorhardware gegossen.
Nein, aber es kann in C durch primitive Datentypen dargestellt werden, welche letztendlich nur Container im Speicher sind und dementsprechend schnell.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Donnerstag 15. Mai 2008, 13:59

Es sieht fast so aus, als ob Rundungsfehler entstehen würden:

Code: Alles auswählen

print (100000000000000000000000*(float(169)/float(13))).__repr__()
gibt nur 1.2999999999999999e+24 aus.

Anderseits lässt sich das Zeugs auch nicht anständig runden:

Code: Alles auswählen

import math as m
print (100000000000000000000000*(m.floor(float(169)/float(13)+0.5))).__repr__()
gibt ebenfalls nur 1.2999999999999999e+24 aus.

Ich arbeite derzeit mit floats (funktioniert fein), muss aber darauf achten,
dass sich meine Rundungsfehler im Extremfall nicht hochschaukeln.
Wahrscheinlich ist es am besten, nach jedem größeren Schritt abzurunden. Aber das scheint auch fehlzuschlagen.

@Darii:
Ich importiere Numeric und arbeite mit einem Array von Floats. Aus der Sicht von Numeric ist die Behandlung von Longs und allgemeinen anderen Klassen anscheinend gleichermaßen langsam. Das Runden von Array-Einträgen scheint auch nicht direkt zu sein
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Donnerstag 15. Mai 2008, 14:15

Das hat nichts mit dem Runden beim Rechnen zu tun, sondern damit, dass 1.3e24 als Float nicht exakt dargestellt werden kann:

Code: Alles auswählen

>>> 1.3e24
1.2999999999999999e+24
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Donnerstag 15. Mai 2008, 14:22

Ich verstehe nicht, wieso Du mit floats arbeiten mußt. Und warum Numeric?

Code: Alles auswählen

In [15]: a = 169 * 100000000000000000000000

In [16]: a
Out[16]: 16900000000000000000000000L

In [17]: b = 13 * 100000000000000000000000

In [18]: a/b
Out[18]: 13L
...
In [22]: a = numpy.array([1, 100, 10000, 1000000, 100000000, 16900000000000000000000000])

In [23]: a/a
Out[23]: array([1, 1, 1, 1, 1, 1], dtype=object)

In [24]: a/13
Out[24]: array([0, 7, 769, 76923, 7692307, 1300000000000000000000000], dtype=object)
BlackJack

Donnerstag 15. Mai 2008, 14:52

Ansonsten käme `numpy` auch noch mit 64-Bit-Integern zurecht. Falls das als Wertebereich ausreicht.
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Donnerstag 15. Mai 2008, 15:18

@Rebecca:
Sehr gute Bemerkung, danke! In der Tat erhalten wir bei

Code: Alles auswählen

print (10000000000000000000000*(float(169)/float(13))).__repr__()
die Ausgabe 1.3e+23.

Tja, bedeutet das wohl, dass bei einer float-Division vielleicht doch keine unnötigen Rundungsfehler entstehen? Schön wäre es ja.
Antworten