wake-up-neo.com

Sicherste Methode, um Float in Python in eine Ganzzahl umzuwandeln?

Das Mathematikmodul von Python enthält nützliche Funktionen wie floor & ceil. Diese Funktionen nehmen eine Fließkommazahl und geben die nächste Ganzzahl darunter oder darüber zurück. Diese Funktionen geben die Antwort jedoch als Fließkommazahl zurück. Zum Beispiel:

import math
f=math.floor(2.3)

Jetzt gibt f zurück:

2.0

Was ist der sicherste Weg, um eine Ganzzahl aus diesem Float herauszuholen, ohne Rundungsfehler zu riskieren (z. B. wenn der Float 1.99999 entspricht) oder vielleicht sollte ich eine andere Funktion insgesamt verwenden?

172
Boaz

Alle Ganzzahlen, die durch Fließkommazahlen dargestellt werden können, sind exakt dargestellt. So können Sie sicher int für das Ergebnis verwenden. Ungenaue Darstellungen treten nur auf, wenn Sie versuchen, eine rationale Zahl mit einem Nenner darzustellen, der keine Zweierpotenz ist.

Dass dies funktioniert, ist überhaupt nicht trivial! Es ist eine Eigenschaft der IEEE-Gleitkommadarstellung, dass int∘floor = ⌊⋅⌋ ist, wenn die Größe der fraglichen Zahlen klein genug ist, aber unterschiedliche Repräsentationen möglich sind, wobei int (floor (2.3)) 1 sein kann.

Zitat aus Wikipedia ,

Jede ganze Zahl mit einem absoluten Wert kleiner oder gleich 224 kann im Format mit einfacher Genauigkeit genau dargestellt werden, und jede ganze Zahl mit einem absoluten Wert kleiner oder gleich 253 kann exakt im Double-Precision-Format dargestellt werden.

150
Philipp

Verwenden Sie int(your non integer number), um es fertig zu stellen.

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"
91
srodriguex

Sie könnten die Rundenfunktion verwenden. Wenn Sie keinen zweiten Parameter (# der signifikanten Ziffern) verwenden, werden Sie das gewünschte Verhalten erhalten.

IDLE-Ausgabe.

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2
43
Wade73

Wir haben zwei der vorherigen Ergebnisse kombiniert:

int(round(some_float))

Dadurch wird ein Float relativ zuverlässig in eine Ganzzahl umgewandelt.

38
user3763109

Dass dies funktioniert, ist überhaupt nicht trivial! Es ist eine Eigenschaft der IEEE-Gleitkommadarstellung, dass int∘floor = ⌊⋅⌋, wenn die Größe der fraglichen Zahlen klein genug ist, aber verschiedene Darstellungen möglich sind, wobei int (floor (2.3)) 1 sein kann.

In diesem Beitrag wird erklärt, warum es in diesem Bereich funktioniert .

In einem Double können Sie problemlos 32-Bit-Ganzzahlen darstellen. Es kann keine Rundungsprobleme geben . Genauer gesagt, Doubles können alle ganzen Zahlen zwischen und einschließlich 2 darstellen53 und - 253.

Kurze Erklärung: Ein Double kann bis zu 53 Binärziffern speichern. Wenn Sie mehr benötigen, wird die Zahl rechts mit Nullen aufgefüllt.

Daraus folgt, dass 53 Einsen die größte Zahl sind, die ohne Auffüllen gespeichert werden kann. Natürlich können alle (ganzzahligen) Zahlen, die weniger Ziffern erfordern, genau gespeichert werden.

Wenn man eins zu 111 (weggelassen) 111 (53 Einsen) addiert, erhält man 100 ... 000 (53 Nullen). Wie wir wissen, können wir 53 Ziffern speichern, sodass der Abstand ganz rechts Null ist.

Hier ist 253 kommt von.


Weitere Details: Wir müssen uns überlegen, wie IEEE-754-Gleitkomma funktioniert.

  1 bit    11 / 8     52 / 23      # bits double/single precision
[ sign |  exponent | mantissa ]

Die Anzahl errechnet sich dann wie folgt (ausgenommen hier irrelevante Sonderfälle):

- 1zeichen × 1. Mantisse × 2exponent - Bias

wobei bias = 2 istexponent - 1 - 1 , d. H. 1023 und 127 für doppelte bzw. einfache Genauigkeit.

Wissen, dass die Multiplikation mit 2X verschiebt einfach alle Bits X nach links. Es ist leicht zu erkennen, dass jede Ganzzahl alle Bits enthalten muss in der Mantisse, die rechts vom Komma auf Null endet.

Jede Ganzzahl außer Null hat die folgende binäre Form:

1x ... x wobei die x - es die Bits bis darstellen das Recht des MSB (höchstwertiges Bit).

Da wir null ausgeschlossen haben, wird immer ein einziges MSB vorhanden sein, weshalb es nicht gespeichert wird. Um die ganze Zahl zu speichern, müssen wir sie in die oben genannte Form bringen: - 1zeichen × 1. Mantisse × 2exponent - Bias.

Das ist das Gleiche wie das Verschieben der Bits über den Dezimalpunkt, bis sich nur noch das MSB links vom MSB befindet. Alle Bits rechts vom Dezimalpunkt werden dann in der Mantisse gespeichert.

Daraus können wir ersehen, dass wir außer dem MSB maximal 52 Binärziffern speichern können.

Daraus folgt, dass die höchste Zahl, in der alle Bits explizit gespeichert sind, ist

111(omitted)111.   that's 53 ones (52 + implicit 1) in the case of doubles.

Dazu müssen wir den Exponenten so einstellen, dass der Dezimalpunkt um 52 Stellen verschoben wird. Wenn wir den Exponenten um eins erhöhen, können wir die Stelle rechts nach dem Komma nicht kennen.

111(omitted)111x.

Konventionell ist es 0. Wenn wir die gesamte Mantisse auf Null setzen, erhalten wir die folgende Zahl:

100(omitted)00x. = 100(omitted)000.

Das ist eine 1 gefolgt von 53 Nullen, 52 gespeichert und 1 aufgrund des Exponenten hinzugefügt.

Es steht für 253, das die Grenze (sowohl negativ als auch positiv) markiert, zwischen der wir alle ganzen Zahlen genau darstellen können. Wenn wir eins zu 2 hinzufügen wollen53, wir müssten die implizite Null (bezeichnet mit x) auf eins setzen, aber das ist unmöglich.

18
phant0m

math.floor liefert immer eine ganze Zahl und int(math.floor(some_float)) führt daher niemals zu Rundungsfehlern.

Der Rundungsfehler wird jedoch möglicherweise bereits in math.floor(some_large_float) eingeführt oder sogar, wenn eine große Zahl in einem Float gespeichert wird. (Große Zahlen können an Genauigkeit verlieren, wenn sie in Schwimmern gespeichert werden.)

5
user3850

Wenn Sie einen String-Float in ein int konvertieren müssen, können Sie diese Methode verwenden.

Beispiel: '38.0' bis 38

Um dies in ein int zu konvertieren, können Sie es als Float und dann als int. Dies funktioniert auch für Float-Strings oder Ganzzahl-Strings.

>>> int(float('38.0'))
38
>>> int(float('38'))
38

Hinweis : Dies entfernt alle Zahlen nach der Dezimalstelle.

>>> int(float('38.2'))
38
4
brandonbanks

Ein weiteres Codebeispiel zum Konvertieren eines Real/Float-Objekts in eine Ganzzahl mithilfe von Variablen . "Vel" ist eine Real/Float-Nummer und wird in den nächsthöheren INTEGER-Wert "newvel" konvertiert.

import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
 for row in cursor:
    curvel = float(row[1])
    newvel = int(math.ceil(curvel))
1
mrichey56

Da Sie nach dem "sichersten" Weg fragen, werde ich eine andere Antwort als die oberste Antwort geben.

Eine einfache Möglichkeit, um sicherzustellen, dass Sie keine Genauigkeit verlieren, besteht darin, zu prüfen, ob die Werte nach der Konvertierung gleich sind. 

if int(some_value) == some_value:
     some_value = int(some_value)

Wenn der Float beispielsweise 1,0 ist, ist 1,0 gleich 1. Die Konvertierung in int wird also ausgeführt. Wenn der Float 1.1 ist, entspricht int (1.1) 1 und 1.1! = 1. Der Wert bleibt also ein Float und Sie verlieren keine Genauigkeit.

0
Troy H