512 Stimmen

Was ist der beste Weg, um in Python Floats auf fast Gleichheit zu vergleichen?

Es ist bekannt, dass Vergleichen von Gleitkommazahlen auf Gleichheit aufgrund von Rundungs- und Präzisionsproblemen etwas kompliziert ist.

Zum Beispiel: Vergleichen von Gleitkommazahlen, Ausgabe 2012

Was ist der empfohlene Weg, um damit in Python umzugehen?

Gibt es irgendwo eine Standardbibliotheksfunktion dafür?

0 Stimmen

@tolomea: Da es von Ihrer Anwendung, Ihren Daten und Ihrem Problem abhängt - und es sich nur um eine Zeile Code handelt -, warum sollte es eine "Standardbibliotheksfunktion" geben?

14 Stimmen

@S.Lott: all, any, max, min sind im Grunde genommen Einzeiler, und sie werden nicht nur in einer Bibliothek bereitgestellt, sondern sind eingebaute Funktionen. Die Gründe des BDFL sind also nicht das. Die eine Zeile Code, die die meisten Menschen schreiben, ist ziemlich einfallslos und funktioniert oft nicht, was ein starkes Argument dafür ist, etwas Besseres bereitzustellen. Natürlich müsste ein Modul, das andere Strategien bietet, auch Warnhinweise bereitstellen, wann sie angemessen sind und vor allem wann nicht. Numerische Analyse ist schwierig, es ist kein großes Unglück, dass Sprachdesigner normalerweise keine Tools zur Unterstützung dabei entwickeln.

0 Stimmen

@Steve Jessop. Diese sammlungsbasierten Funktionen haben nicht die Anwendungs-, Daten- und Problemdomänenabhängigkeiten wie Gleitkommazahlen. Daher ist der "Einzeiler" offensichtlich nicht so wichtig wie die eigentlichen Gründe. Die numerische Analyse ist schwierig und kann kein integraler Bestandteil einer Library einer allgemeinen Zwecksprache sein.

0voto

Vlad Punkte 7637

Um bis zu einer bestimmten Dezimalstelle zu vergleichen, ohne atol/rtol:

def fast_gleich(a, b, dezimal=6):
    return '{0:.{1}f}'.format(a, dezimal) == '{0:.{1}f}'.format(b, dezimal)

print(fast_gleich(0.0, 0.0001, dezimal=5)) # False
print(fast_gleich(0.0, 0.0001, dezimal=4)) # True

0voto

Ilmari Kumpula Punkte 388

Wenn Sie Floats vergleichen möchten, sind die oben genannten Optionen großartig, aber in meinem Fall habe ich Enum's verwendet, da ich nur wenige gültige Floats hatte, die mein Anwendungsfall akzeptierte.

from enum import Enum
class HolidayMultipliers(Enum):
    EMPLOYED_LESS_THAN_YEAR = 2.0
    EMPLOYED_MORE_THAN_YEAR = 2.5

Dann führen Sie aus:

testable_value = 2.0
HolidayMultipliers(testable_value)

Wenn der Float gültig ist, ist das in Ordnung, ansonsten wird einfach ein ValueError ausgelöst.

-2voto

Walulya francis Punkte 151

Ziemlich lahm, aber es funktioniert trotzdem

  def isEqual(f1, f2):
        f1 = float(f1)
        f2 = float(f2)
        ans1 = f1-f2
        ans2 = f2-f1
        return (ans1 == ans2)

Verwendung

 f1 = 4.000444
 f2 = 4.0
 print(isEqual(f1, f2))
 print(isEqual(f2, f2))

Sie können auch für die Annäherungsgleichheit runden

import math

def isEqual(f1, f2):
    f1 = math.ceil(f1)
    f2 = math.ceil(f2)
    ans1 = f1-f2
    ans2 = f2-f1
    return (ans1 == ans2)

was ich nicht weiß, ob es effizient für Ihre Anwendung ist!

-3voto

Yan QiDong Punkte 2664

Die Verwendung von == ist eine einfache gute Methode, wenn Sie sich nicht genau um Toleranz kümmern.

# Python 3.8.5
>>> 1.0000000000001 == 1
False
>>> 1.00000000000001 == 1
True

Aber achten Sie auf 0:

>>> 0 == 0.00000000000000000000000000000000000000000001
False

Die 0 ist immer die Null.


Verwenden Sie math.isclose, wenn Sie die Toleranz kontrollieren möchten.

Das Standardverhalten von a == b entspricht math.isclose(a, b, rel_tol=1e-16, abs_tol=0).


Wenn Sie trotzdem == mit einer selbstdefinierten Toleranz verwenden möchten:

>>> class MyFloat(float):
        def __eq__(self, another):
        return math.isclose(self, another, rel_tol=0, abs_tol=0.001)

>>> a == MyFloat(0)
>>> a
0.0
>>> a == 0.001
True

Bisher habe ich keinen globalen Ort gefunden, um es für float zu konfigurieren. Außerdem funktioniert mock auch nicht für float.__eq__.

1 Stimmen

Sie können es nicht global konfigurieren, weil es keine Toleranz anwendet, sondern die tatsächlichen Bitwerte vergleicht. Während C Python C-Doubles verwendet, ist dies nicht in der Spezifikation erforderlich. Es könnte sich in Zukunft ändern, und andere Python-Varianten könnten andere Dinge tun. Das Vergleichen von Gleitkommazahlen mit == kann also je nach Umgebung unterschiedliche Ergebnisse liefern.

0 Stimmen

Ja, ich lag falsch. 1 + 1e-16 == 1 in Python, nur weil 1 + 1e-16 nach dem Verlust der Genauigkeit 1.0 ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X