Ich möchte Ziffern aus einem Float entfernen, um eine feste Anzahl von Ziffern nach dem Punkt zu erhalten, wie z.
1.923328437452 -> 1.923
Ich muss als Zeichenfolge für eine andere Funktion ausgeben, nicht drucken.
Außerdem möchte ich die verlorenen Ziffern ignorieren und nicht umrunden.
python
floating-point
Joan Venge
quelle
quelle
Antworten:
Erstens die Funktion für diejenigen, die nur Code zum Kopieren und Einfügen benötigen:
Dies gilt in Python 2.7 und 3.1+. Bei älteren Versionen ist es nicht möglich, den gleichen "intelligenten Rundungseffekt" zu erzielen (zumindest nicht ohne viel komplizierten Code), aber das Runden auf 12 Dezimalstellen vor dem Abschneiden funktioniert meistens:
Erläuterung
Der Kern der zugrunde liegenden Methode besteht darin, den Wert mit voller Genauigkeit in eine Zeichenfolge umzuwandeln und dann einfach alles über die gewünschte Anzahl von Zeichen hinaus abzuschneiden. Der letzte Schritt ist einfach; Dies kann entweder mit String-Manipulation erfolgen
oder das
decimal
ModulDer erste Schritt, die Konvertierung in eine Zeichenfolge, ist ziemlich schwierig, da es einige Paare von Gleitkomma-Literalen gibt (dh was Sie im Quellcode schreiben), die beide dieselbe Binärdarstellung erzeugen und dennoch unterschiedlich abgeschnitten werden sollten. Betrachten Sie beispielsweise 0,3 und 0,29999999999999998. Wenn Sie
0.3
in ein Python-Programm schreiben , codiert der Compiler es im IEEE-Gleitkommaformat in die Bitfolge (unter der Annahme eines 64-Bit-Gleitkommas).Dies ist der Wert, der 0,3 am nächsten kommt und genau als IEEE-Float dargestellt werden kann. Wenn Sie jedoch
0.29999999999999998
in ein Python-Programm schreiben , übersetzt der Compiler es in genau denselben Wert . In einem Fall haben Sie gemeint, dass es abgeschnitten wird (auf eine Ziffer)0.3
, während Sie in dem anderen Fall gemeint haben, dass es abgeschnitten wird0.2
, aber Python kann nur eine Antwort geben. Dies ist eine grundlegende Einschränkung von Python oder einer anderen Programmiersprache ohne verzögerte Auswertung. Die Kürzungsfunktion hat nur Zugriff auf den im Speicher des Computers gespeicherten Binärwert, nicht auf die Zeichenfolge, die Sie tatsächlich in den Quellcode eingegeben haben. 1Wenn Sie die Bitfolge wieder in eine Dezimalzahl dekodieren und erneut das IEEE 64-Bit-Gleitkommaformat verwenden, erhalten Sie
Eine naive Implementierung würde sich also einfallen lassen,
0.2
obwohl Sie das wahrscheinlich nicht wollen. Weitere Informationen zum Gleitkomma-Darstellungsfehler finden Sie im Python-Lernprogramm .Es ist sehr selten, mit einem Gleitkommawert zu arbeiten, der einer runden Zahl so nahe kommt und dennoch absichtlich nicht dieser runden Zahl entspricht. Wenn Sie also abschneiden, ist es wahrscheinlich sinnvoll, die "schönste" Dezimaldarstellung aus allen auszuwählen, die dem Wert im Speicher entsprechen könnten. Python 2.7 und höher (aber nicht 3.0) enthält einen ausgeklügelten Algorithmus , auf den wir über die Standardformatierungsoperation für Zeichenfolgen zugreifen können.
Die einzige Einschränkung besteht darin, dass dies wie eine Formatspezifikation wirkt
g
, in dem Sinne, dass die Exponentialnotation (1.23e+4
) verwendet wird, wenn die Zahl groß oder klein genug ist. Die Methode muss diesen Fall also erfassen und anders behandeln. Es gibt einige Fälle, in denen die Verwendung einerf
Formatspezifikation stattdessen ein Problem verursacht, z. B. der Versuch, die3e-10
Genauigkeit auf 28 Stellen abzuschneiden (dies führt zu0.0000000002999999999999999980
), und ich bin mir noch nicht sicher, wie ich mit diesen am besten umgehen soll.Wenn Sie tatsächlich sind mit Arbeits
float
s , die sehr nah an runden Zahlen sind aber absichtlich gleich sie nicht (wie ,29999999999999998 oder 99,959999999999994), wird dies einige Fehlalarme produzieren, das heißt , es werden rund um Zahlen , dass Sie nicht gerundet haben wollten. In diesem Fall besteht die Lösung darin, eine feste Genauigkeit anzugeben.Die Anzahl der hier zu verwendenden Genauigkeitsziffern spielt keine Rolle, sie muss nur groß genug sein, um sicherzustellen, dass bei der bei der Zeichenfolgenkonvertierung durchgeführten Rundung der Wert nicht auf seine schöne Dezimaldarstellung "erhöht" wird. Ich denke, es
sys.float_info.dig + n + 2
kann in allen Fällen ausreichen, aber wenn nicht, muss das2
möglicherweise erhöht werden, und es tut nicht weh, dies zu tun.In früheren Versionen von Python (bis zu 2.6 oder 3.0) war die Formatierung von Gleitkommazahlen viel gröber und erzeugte regelmäßig Dinge wie
Wenn dies Ihre Situation ist und Sie "schöne" Dezimaldarstellungen zum Abschneiden verwenden möchten, können Sie (soweit ich weiß) nur eine Anzahl von Ziffern auswählen, die unter der durch a darstellbaren vollen Genauigkeit liegen
float
, und die Zahl abrunden Nummerieren Sie diese Anzahl, bevor Sie sie abschneiden. Eine typische Wahl ist 12,Sie können dies jedoch an die von Ihnen verwendeten Zahlen anpassen.
1 Nun ... ich habe gelogen. Technisch Sie können Python anweisen , seinen eigenen Quellcode neu zu analysieren und den Teil , den Sie zum Abschneiden Funktion übergeben , um das erste Argument entspricht , zu extrahieren. Wenn dieses Argument ein Gleitkomma-Literal ist, können Sie es einfach um eine bestimmte Anzahl von Stellen nach dem Dezimalpunkt abschneiden und dieses zurückgeben. Diese Strategie funktioniert jedoch nicht, wenn das Argument eine Variable ist, was es ziemlich nutzlos macht. Folgendes wird nur zum Unterhaltungswert dargestellt:
Dies zu verallgemeinern, um den Fall zu behandeln, in dem Sie eine Variable übergeben, scheint eine verlorene Ursache zu sein, da Sie die Programmausführung rückwärts verfolgen müssten, bis Sie das Gleitkomma-Literal finden, das der Variablen ihren Wert gegeben hat. Wenn es überhaupt einen gibt. Die meisten Variablen werden aus Benutzereingaben oder mathematischen Ausdrücken initialisiert. In diesem Fall ist nur die binäre Darstellung vorhanden.
quelle
applymap()
) angewendet wird . Vielleicht gibt es eine Möglichkeit, den gesamten Vorgang effizienter zu gestalten, aber das wäre eine Frage einer separaten Frage.Weitere Informationen zu den Standardtypen finden Sie in der Python-Dokumentation . Sie müssen ein wenig nach unten scrollen, um zur Rundungsfunktion zu gelangen. Im Wesentlichen gibt die zweite Zahl an, auf wie viele Dezimalstellen gerundet werden soll.
quelle
Das Ergebnis von
round
ist ein Float. Achten Sie also darauf (Beispiel stammt aus Python 2.6):Wenn Sie eine formatierte Zeichenfolge verwenden, sind Sie besser dran:
quelle
round(1.23456, 3)
ist1.235
und nicht1.2350000000000001
quelle
2
, wird.
am Ende der Zeichenfolge ein Dezimalpunkt angezeigt - meiner Meinung nach keine wirklich gute Lösung.An meiner Python 2.7-Eingabeaufforderung:
>>> int(1.923328437452 * 1000)/1000.0 1.923
quelle
Einfaches Python-Skript -
quelle
Das sollte funktionieren. Es sollte Ihnen die Kürzung geben, die Sie suchen.
quelle
Die wirklich pythonische Art, es zu tun, ist
oder kürzer:
Aktualisieren
Normalerweise liegt das Problem nicht darin, Floats selbst abzuschneiden, sondern darin, Float-Zahlen vor dem Runden falsch zu verwenden .
Beispielsweise:
int(0.7*3*100)/100 == 2.09
.Wenn Sie gezwungen sind , Floats zu verwenden (z. B. beschleunigen Sie Ihren Code mit
numba
), ist es besser, Cent als "interne Darstellung" der Preise zu verwenden: (70*3 == 210
) und die Ein- / Ausgänge zu multiplizieren / zu dividieren.quelle
int(0.7*3*100)/100 == 2.09
. Wo ist mein 1 Cent geblieben?ImportError: cannot import name 'D'
, ich glaube, Sie wollten eine benannte Import-Nr. Machen?So viele der Antworten auf diese Frage sind einfach völlig falsch. Sie runden entweder Floats auf (anstatt sie abzuschneiden) oder funktionieren nicht in allen Fällen.
Dies ist das beste Google-Ergebnis, wenn ich nach "Python truncate float" suche, einem Konzept, das wirklich einfach ist und bessere Antworten verdient. Ich stimme Hatchkins zu, dass die Verwendung der
decimal
Moduls die pythonische Methode ist, daher gebe ich hier eine Funktion, die meiner Meinung nach die Frage richtig beantwortet und in allen Fällen wie erwartet funktioniert.Als Randnotiz können Bruchwerte im Allgemeinen nicht genau durch binäre Gleitkommavariablen dargestellt werden (siehe hier für eine Diskussion darüber), weshalb meine Funktion einen String zurückgibt.
quelle
Ich habe so etwas gemacht:
quelle
Du kannst tun:
testen:
quelle
Wenn Sie sich für Mathematik interessieren, funktioniert dies für + ve Zahlen:
quelle
Bei der Verwendung eines Pandas df hat dies bei mir funktioniert
quelle
Ich wollte nur erwähnen, dass der alte Trick "make round () with floor ()" von
kann gedreht werden, um floor () aus round () zu machen
Obwohl diese beiden Regeln um negative Zahlen herum brechen, ist ihre Verwendung nicht ideal:
quelle
int (16,5); Dies ergibt einen ganzzahligen Wert von 16, dh Trunc, kann keine Dezimalstellen angeben, aber Sie können dies mit tun
quelle
Hier ist ein einfacher Weg:
für num = 1.923328437452 gibt dies 1.923 aus
quelle
quelle
Eine allgemeine und einfache Funktion:
quelle
In Python 3 gibt es eine einfache Problemumgehung. Wo geschnitten werden soll Ich habe mit einer Hilfevariablen decPlace definiert, um die Anpassung zu vereinfachen.
Ausgabe:
Ich hoffe es hilft.
quelle
quelle
Kurze und einfache Variante
quelle
Die meisten Antworten sind meiner Meinung nach viel zu kompliziert. Wie wäre es damit?
Scannen Sie einfach nach dem Index von '.' und wie gewünscht abschneiden (keine Rundung). Konvertieren Sie den String als letzten Schritt in Float.
Oder in Ihrem Fall, wenn Sie einen Float als Eingabe erhalten und einen String als Ausgabe möchten:
quelle
# dividieren und multiplizieren Sie mit 10 ** Anzahl der gewünschten Ziffern
quelle
benutze numpy.round
quelle
Etwas, das einfach genug ist, um in ein Listenverständnis zu passen, ohne Bibliotheken oder andere externe Abhängigkeiten. Für Python> = 3.6 ist es sehr einfach, mit F-Strings zu schreiben.
Die Idee ist, die String-Konvertierung die Rundung auf eine Stelle mehr als nötig durchführen zu lassen und dann die letzte Ziffer abzuschneiden.
Natürlich findet hier eine Rundung statt (nämlich für die vierte Ziffer), aber irgendwann ist eine Rundung unvermeidlich. Für den Fall, dass der Übergang zwischen Abschneiden und Runden relevant ist, hier ein etwas besseres Beispiel:
Bonus: Nullen rechts entfernen
quelle
Die hier gegebene Kernidee scheint mir der beste Ansatz für dieses Problem zu sein. Leider hat es weniger Stimmen erhalten, während die spätere Antwort mit mehr Stimmen nicht vollständig ist (wie in den Kommentaren angegeben). Hoffentlich bietet die folgende Implementierung eine kurze und vollständige Lösung für das Abschneiden .
die sich um alle hier und hier gefundenen Eckfälle kümmern sollte .
quelle
Ich bin auch ein Python-Neuling und nachdem ich hier ein paar Kleinigkeiten verwendet habe, biete ich meine zwei Cent an
str (int (time.time ())) nimmt die Zeitepoche als int und konvertiert sie in einen String und verbindet sich mit ... str (datetime.now (). microsecond) [: 3], das nur die Mikrosekunden zurückgibt, convert auf die ersten 3 Zeichen setzen und abschneiden
quelle
quelle
Wenn Sie beim Drucken meinen, sollte Folgendes funktionieren:
quelle