Python Float to Int-Konvertierung

73

Grundsätzlich konvertiere ich einen Float in einen Int, aber ich habe nicht immer den erwarteten Wert.

Hier ist der Code, den ich ausführe:

x = 2,51

print("--------- 251.0")
y = 251.0
print(y)
print(int(y))

print("--------- 2.51 * 100")
y = x * 100
print(y)
print(int(y))

print("--------- 2.51 * 1000 / 10")
y = x * 1000 / 10
print(y)
print(int(y))

print("--------- 2.51 * 100 * 10 / 10")
y = x * 100 * 10 / 10
print(y)
print(int(y))

x = 4.02
print("--------- 402.0")
y = 402.0
print(y)
print(int(y))

print("--------- 4.02 * 100")
y = x * 100
print(y)
print(int(y))

print("--------- 4.02 * 1000 / 10")
y = x * 1000 / 10
print(y)
print(int(y))

print("--------- 4.02 * 100 * 10 / 10")
y = x * 100 * 10 / 10
print(y)
print(int(y))

Und hier ist das Ergebnis (der erste Wert ist das Ergebnis der Operation, der zweite Wert ist int () derselben Operation):

--------- 251.0
251.0
251
--------- 2.51 * 100
251.0
250
--------- 2.51 * 1000 / 10
251.0
251
--------- 2.51 * 100 * 10 / 10
251.0
250
--------- 402.0
402.0
402
--------- 4.02 * 100
402.0
401
--------- 4.02 * 1000 / 10
402.0
401
--------- 4.02 * 100 * 10 / 10
402.0
401

2,51 und 4,02 sind die einzigen Werte, die zu diesem seltsamen Verhalten im Bereich von 2,50 -> 5,00 führen. Alle zwei zweistelligen Werte in diesem Bereich werden bei gleichen Operationen problemlos in int konvertiert.

Was fehlt mir also, was zu diesen Ergebnissen führt? Ich benutze übrigens Python 2.7.2.

B. Richard
quelle
Gleitkommawerte stellen Dezimalstellen nicht genau dar. Dies ist keine Python-Sache.
Daniel Roseman
Mögliches Duplikat des Python-Rundungsfehlers mit Gleitkommazahlen
Mac
Während andere erklärten, warum dies passiert, möchte ich meine nfloor = lambda x: round(x * 10**8) // 10**8
Problemumgehung

Antworten:

93
2.51 * 100 = 250.999999999997

Die int()Funktion schneidet einfach die Zahl am Dezimalpunkt ab und ergibt 250. Verwenden Sie

int(round(2.51*100)) 

251 als ganze Zahl zu erhalten. Im Allgemeinen können Gleitkommazahlen nicht genau dargestellt werden. Man sollte daher auf Rundungsfehler achten. Wie bereits erwähnt, ist dies kein Python-spezifisches Problem. Es ist ein wiederkehrendes Problem in allen Computersprachen.

Pascal Bugnion
quelle
32

Was jeder Informatiker über Gleitkomma-Arithmetik wissen sollte

Gleitkommazahlen können nicht alle Zahlen darstellen. Insbesondere kann 2.51 nicht durch eine Gleitkommazahl dargestellt werden und wird durch eine Zahl sehr nahe daran dargestellt:

>>> print "%.16f" % 2.51
2.5099999999999998
>>> 2.51*100
250.99999999999997
>>> 4.02*100
401.99999999999994

Wenn Sie int verwenden, wodurch die Zahlen abgeschnitten werden, erhalten Sie:

250
401

Schauen Sie sich den Dezimaltyp an .

Jakob
quelle
4
"Gleitkommazahlen sind nicht 100% genau" würde am genauesten in der Zeile "Nicht alle Zahlen können durch Gleitkommazahlen dargestellt werden" beschrieben werden (ein Zahlenliteral wird in eine Gleitkommazahl umgewandelt, die sehr nahe beieinander liegt). und manchmal identisch mit der Nummer). Tatsächlich repräsentieren alle Gleitkommazahlen genau den Wert, den sie repräsentieren. Der entscheidende Punkt ist, dass sie nicht alle möglichen Zahlen darstellen.
Eric O Lebigot
@EOL Wenn Sie erlauben, kann ich es bearbeiten oder Sie können es selbst bearbeiten.
Jacob
Vielen Dank. Ich habe Ihre Antwort bearbeitet. Fühlen Sie sich frei, meine Prosa an Ihren Geschmack anzupassen. :)
Eric O Lebigot
1
Das Wichtigste, was Sie über binäre Gleitkommazahlen wissen müssen (Sie können dies aus dem verlinkten Artikel entnehmen, aber hier ist eine TL; DR), ist, dass Ziffern nach dem Binärpunkt negative Potenzen von zwei darstellen: eine Hälfte, ein Viertel, eine Achtel usw. Eine binäre Gleitkommazahl kann somit genau nur Brüche darstellen, die eine Summe von negativen Potenzen von zwei sind, die durch die verfügbaren Bits darstellbar sind. Bestimmte Brüche, die in Dezimalschreibweise endlich sind (z. B. 0,1), erfordern eine unendliche Anzahl von Bits in Binärschreibweise und können daher nicht vollständig in einem Teil dargestellt werden, floatder eine endliche Anzahl von Bits aufweist.
Kindall
11

Sprachen, die binäre Gleitkomma-Darstellungen verwenden (Python ist eine), können nicht alle Bruchwerte genau darstellen. Wenn das Ergebnis Ihrer Berechnung 250.99999999999 ist (und es könnte sein), führt die Verwendung des ganzzahligen Teils zu 250.

Ein kanonischer Artikel zu diesem Thema ist das, was jeder Informatiker über Gleitkomma-Arithmetik wissen sollte .

Greg Hewgill
quelle
7
>>> x = 2.51
>>> x*100
250.99999999999997

Die Gleitkommazahlen sind ungenau. In diesem Fall ist es 250.9999999999999999, was sehr nahe an 251 liegt, aber int () schneidet den Dezimalteil ab, in diesem Fall 250.

Sie sollten sich das Dezimalmodul ansehen oder wenn Sie in der mpmath-Bibliothek http://code.google.com/p/mpmath/ :) viel rechnen müssen.

Ameise
quelle
3
int()rundet nicht auf die Ganzzahl unten, sondern schneidet den Dezimalteil ab. Beispiel : int(-0.9) == 0.
Eric O Lebigot
1

intkonvertiert durch Abschneiden, wie von anderen erwähnt wurde. Dies kann dazu führen, dass die Antwort anders als erwartet ist. Eine Möglichkeit, dies zu umgehen, besteht darin, zu überprüfen, ob das Ergebnis nahe genug an einer Ganzzahl liegt, und es entsprechend anzupassen, andernfalls die übliche Konvertierung. Dies setzt voraus, dass Sie nicht zu viele Rundungs- und Berechnungsfehler erhalten, was ein separates Problem ist. Zum Beispiel:

def toint(f):
    trunc = int(f)
    diff = f - trunc

    # trunc is one too low
    if abs(f - trunc - 1) < 0.00001:
        return trunc + 1
    # trunc is one too high
    if abs(f - trunc + 1) < 0.00001:
        return trunc - 1
    # trunc is the right value
    return trunc

Diese Funktion passt Off-by-One-Fehler für nahe ganze Zahlen an. Die mpmathBibliothek macht etwas Ähnliches für Gleitkommazahlen, die nahe an ganzen Zahlen liegen.

HackerBoss
quelle