wake-up-neo.com

Begrenzung von Gleitkommazahlen auf zwei Dezimalstellen

Ich möchte, dass a auf 13,95 gerundet wird.

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

Die Funktion round funktioniert nicht wie erwartet.

1449
kevin

Sie stoßen auf das altes Problem mit Gleitkommazahlen, dass nicht alle Zahlen exakt dargestellt werden können. In der Befehlszeile wird nur das vollständige Gleitkommaformular aus dem Speicher angezeigt.

Bei der Gleitkommadarstellung hat Ihre gerundete Version dieselbe Nummer. Da Computer binär sind, speichern sie Gleitkommazahlen als Ganzzahl und dividieren sie dann durch eine Zweierpotenz, sodass 13,95 in ähnlicher Weise wie 125650429603636838/(2 ** 53) dargestellt werden.

Zahlen mit doppelter Genauigkeit haben eine Genauigkeit von 53 Bit (16 Stellen), und reguläre Gleitkommazahlen haben eine Genauigkeit von 24 Bit (8 Stellen). Das Gleitkommatyp in Python verwendet doppelte Genauigkeit , um die Werte zu speichern.

Zum Beispiel,

  >>> 125650429603636838/(2**53)
  13.949999999999999

  >>> 234042163/(2**24)
  13.949999988079071

  >>> a=13.946
  >>> print(a)
  13.946
  >>> print("%.2f" % a)
  13.95
  >>> round(a,2)
  13.949999999999999
  >>> print("%.2f" % round(a,2))
  13.95
  >>> print("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Wenn Sie nur nach zwei Dezimalstellen suchen (um beispielsweise einen Währungswert anzuzeigen), haben Sie eine Reihe besserer Möglichkeiten:

  1. Verwenden Sie Ganzzahlen und speichern Sie Werte in Cent, nicht in Dollar, und dividieren Sie sie durch 100, um sie in Dollar umzurechnen.
  2. Oder verwenden Sie eine Festkommazahl wie dezimal .
1441
Rex Logan

Es gibt neue Formatspezifikationen, String Format Specification Mini-Language :

Sie können das Gleiche tun wie:

"{0:.2f}".format(13.949999999999999)

Beachten Sie , dass oben eine Zeichenfolge zurückgegeben wird. Um als float zu erhalten, wickeln Sie einfach mit float(...):

float("{0:.2f}".format(13.949999999999999))

Beachten Sie , dass das Umbrechen mit float() nichts ändert:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
516
Xolve

Die eingebaute Funktion round() funktioniert in Python 2.7 oder höher einwandfrei.

Beispiel:

>>> round(14.22222223, 2)
14.22

Check out die Dokumentation .

244
chribsen

Ich bin der Meinung, dass der einfachste Ansatz darin besteht, die Funktion format() zu verwenden.

Zum Beispiel:

a = 13.949999999999999
format(a, '.2f')

13.95

Dies erzeugt eine Gleitkommazahl als Zeichenfolge, die auf zwei Dezimalstellen gerundet wird.

133
grant zukowski

Die meisten Zahlen können nicht exakt in Gleitkommazahlen dargestellt werden. Wenn Sie die Zahl runden möchten, weil dies für Ihre mathematische Formel oder Ihren Algorithmus erforderlich ist, möchten Sie round verwenden. Wenn Sie die Anzeige nur auf eine bestimmte Genauigkeit beschränken möchten, verwenden Sie nicht einmal round und formatieren Sie sie einfach als diese Zeichenfolge. (Wenn Sie es mit einer alternativen Rundungsmethode anzeigen möchten und es Tonnen gibt, müssen Sie die beiden Ansätze mischen.)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

Und zum Schluss, vielleicht am wichtigsten, wenn Sie gena Mathe wollen, dann wollen Sie überhaupt keine Schwimmer. Das übliche Beispiel ist der Umgang mit Geld und das Speichern von 'Cent' als Ganzzahl.

90
Roger Pate

Verwenden

print"{:.2f}".format(a)

anstatt von

print"{0:.2f}".format(a)

Denn letzteres kann bei der Ausgabe mehrerer Variablen zu Ausgabefehlern führen (siehe Kommentare).

83

Probieren Sie den folgenden Code aus:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
70
ax003d

Mit Python <3 (z. B. 2.6 oder 2.7) gibt es zwei Möglichkeiten, dies zu tun.

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

Beachten Sie jedoch, dass für Python -Versionen über 3 (z. B. 3.2 oder 3.3) Option zwei bevorzugt ist.

Für weitere Informationen zu Option 2 empfehle ich diesen Link unter Formatierung der Zeichenfolge aus der Dokumentation zu Python .

Und für weitere Informationen zu Option eins dieser Link reicht aus und enthält Informationen zu den verschiedenen Flags .

Referenz: Gleitkommazahl auf eine bestimmte Genauigkeit umwandeln und dann in eine Zeichenfolge kopieren

51
A.J.

TLDR;)

Das Rundungsproblem der Eingabe/Ausgabe wurde endgültig durch Python 2.7.0 und gelöst. 3,1 .

Eine richtig gerundete Zahl kann reversibel vor und zurück konvertiert werden:
str -> float() -> repr() -> float() ... oder Decimal -> float -> str -> Decimal
Ein Dezimaltyp ist für die Speicherung nicht mehr erforderlich.


(Natürlich kann es notwendig sein, ein Ergebnis der Addition oder Subtraktion von gerundeten Zahlen zu runden, um die akkumulierten Fehler des letzten Bits zu beseitigen. Eine explizite Dezimalarithmetik kann immer noch nützlich sein, aber eine Umwandlung in einen String durch str() (dh mit Das Runden auf 12 gültige Stellen ist in der Regel ausreichend, wenn keine extreme Genauigkeit oder keine extreme Anzahl aufeinanderfolgender arithmetischer Operationen erforderlich ist.

Unendlicher Test :

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Dokumentation

Siehe Versionshinweise Python 2.7 - Andere Sprachänderungen den vierten Absatz:

Umrechnungen zwischen Gleitkommazahlen und Zeichenketten werden jetzt auf den meisten korrekt gerundet Plattformen. Diese Konvertierungen finden an vielen verschiedenen Stellen statt: str () für Gleitkommazahlen und komplexe Zahlen; der Schwimmer und komplexe Konstrukteure; numerische Formatierung; Floats und komplexe Zahlen mit den Modulen marshal, pickle und json serialisieren und deserialisieren; Analyse von float und imaginären Literalen in Python Code; und Decimal-to-Float-Konvertierung.

In diesem Zusammenhang gibt das repr () einer Gleitkommazahl x nun ein Ergebnis zurück, das auf dem kürzesten Wert basiert Dezimalzeichenfolge, die bei korrekter Rundung garantiert auf x zurückrundet (mit dem Rundungsmodus "Halbieren auf Gerade"). Zuvor gab es eine Zeichenfolge basierend auf dem Runden von x auf 17 Dezimalstellen.

Das verwandte Problem


Weitere Informationen: Die Formatierung von float vor Python 2.7 war der aktuellen numpy.float64 ähnlich. Beide Typen verwenden dieselbe 64-Bit IEEE 754 doppelte Genauigkeit mit 52-Bit-Mantisse. Ein großer Unterschied besteht darin, dass np.float64.__repr__ häufig mit einer übermäßigen Dezimalzahl formatiert wird, so dass kein Bit verloren gehen kann, jedoch keine gültige IEEE 754-Nummer zwischen 13.9499999999999 und 13.950000000000001 vorhanden ist. Das Ergebnis ist nicht Nice und die Konvertierung repr(float(number_as_string)) ist mit numpy nicht umkehrbar. Auf der anderen Seite: float.__repr__ ist so formatiert, dass jede Ziffer wichtig ist; Die Reihenfolge ist lückenlos und die Konvertierung ist reversibel. Einfach: Wenn Sie vielleicht eine numpy.float64-Nummer haben, konvertieren Sie diese in eine normale float-Nummer, um sie für Menschen zu formatieren, nicht für numerische Prozessoren. Andernfalls ist mit Python 2.7+ nichts mehr erforderlich.

46
hynekcer

Sie können das Ausgabeformat ändern:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
46
Greg Hewgill

Niemand hier scheint es bisher erwähnt zu haben, also lassen Sie mich ein Beispiel im Format f-string/template-string von Python 3.6 geben, das ich für sehr schön halte:

>>> f'{a:.2f}'

Es funktioniert auch mit längeren Beispielen, mit Operatoren und ohne Parens:

>>> print(f'Completed in {time.time() - start:.2f}s')
31
Matt Fletcher

Sie können den Operator Format verwenden, um den Wert in Python auf zwei Dezimalstellen zu runden:

print(format(14.4499923, '.2f')) // output is 14.45
29
Asad Manzoor

In Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
27
Shashank Singh

Das Tutorial Python enthält einen Anhang mit dem Namen Gleitkomma-Arithmetik: Probleme und Einschränkungen. Lies es. Es erklärt, was passiert und warum Python sein Bestes tut. Es gibt sogar ein Beispiel, das zu Ihrem passt. Lassen Sie mich ein bisschen zitieren:

>>> 0.1
0.10000000000000001

sie könnten versucht sein, die Funktion round() zu verwenden, um sie auf die von Ihnen erwartete Ziffer zurückzusetzen. Das macht aber keinen Unterschied:

>>> round(0.1, 1)
0.10000000000000001

Das Problem ist, dass der für “0.1” gespeicherte binäre Gleitkommawert bereits die bestmögliche binäre Annäherung an 1/10 darstellte. Wenn Sie also versuchen, ihn erneut zu runden, kann dies keine Verbesserung bewirken: Er war bereits so gut wie es wird.

Eine andere Konsequenz ist, dass, da 0.1 nicht genau 1/10 ist, das Summieren von zehn Werten von 0.1 möglicherweise auch nicht genau 1.0 ergibt:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

Eine Alternative und Lösung für Ihre Probleme wäre die Verwendung des Moduls decimal .

21
nosklo

Wie @Matt betonte, bietet Python 3.6 f-Strings und sie können auch verschachtelte Parameter verwenden:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

welches result: 2.35 anzeigt

12
toto_tico

Es macht genau das, was Sie ihm gesagt haben und es funktioniert richtig. Lesen Sie mehr über Fließkomma-Verwirrung und versuchen Sie es vielleicht mit Dezimal .

12
HUAGHAGUAH

Zum Festlegen des Gleitkommas in typdynamischen Sprachen wie Python und JavaScript verwende ich diese Technik

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

Sie können Decimal auch wie folgt verwenden:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
7
Siamand
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14,54

6
MikeL
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

Ergebnisse:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
6
weaming

Es ist einfach wie 1,2,3:

  1. benutze decimal Modul für schnelle, korrekt gerundete Fließkomma-Arithmetik:

    d = Dezimal (10000000.0000009)

rundung erreichen:

   d.quantize(Decimal('0.01'))

ergibt sich mit Decimal('10000000.00')

  1. über DRY machen:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. stimme dieser Antwort zu :)

PS: Kritik an anderen: Formatierung ist keine Rundung.

4

Was ist mit einer Lambda-Funktion wie dieser:

arred = lambda x,n : x*(10**n)//1/(10**n)

Auf diese Weise können Sie einfach Folgendes tun:

arred(3.141591657,2)

und bekomme

3.14
3

Verwenden Sie eine Kombination aus Decimal-Objekt und round () -Methode.

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
2
Jonathan L

Der beste Weg, um eine Zahl auf eine Auflösung zu runden, ist der folgende, der mit jeder Auflösung funktionieren kann (0,01 für zwei Dezimalstellen oder sogar andere Schritte):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
1
iblasi