Der folgende Code ist offensichtlich falsch. Was ist das Problem?
i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
r
floating-point
floating-accuracy
r-faq
dplanet
quelle
quelle
Antworten:
Allgemeiner (sprachunabhängiger) Grund
Da nicht alle Zahlen in der IEEE-Gleitkomma-Arithmetik genau dargestellt werden können (der Standard, den fast alle Computer verwenden, um Dezimalzahlen darzustellen und damit zu rechnen), erhalten Sie nicht immer das, was Sie erwartet haben. Dies gilt insbesondere, weil einige Werte, die einfache, endliche Dezimalstellen sind (wie 0,1 und 0,05), im Computer nicht genau dargestellt werden und die Ergebnisse der Arithmetik auf ihnen möglicherweise kein Ergebnis ergeben, das mit einer direkten Darstellung des " bekannte "Antwort.
Dies ist eine bekannte Einschränkung der Computerarithmetik und wird an mehreren Stellen erörtert:
Skalare vergleichen
Die Standardlösung hierfür
R
ist nicht die Verwendung==
, sondern dieall.equal
Funktion. Oder besser gesagt, daall.equal
es viele Details über die Unterschiede gibt, falls es welche gibt ,isTRUE(all.equal(...))
.ergibt
Einige weitere Beispiele für die Verwendung von
all.equal
anstelle von==
(das letzte Beispiel soll zeigen, dass dies die Unterschiede korrekt zeigt).Einige weitere Details, die direkt aus einer Antwort auf eine ähnliche Frage kopiert wurden :
Das Problem, auf das Sie gestoßen sind, ist, dass Gleitkomma in den meisten Fällen keine exakten Dezimalbrüche darstellen kann. Dies bedeutet, dass Sie häufig feststellen, dass exakte Übereinstimmungen fehlschlagen.
während R leicht liegt, wenn Sie sagen:
Sie können herausfinden, was es wirklich in Dezimalzahl denkt:
Sie können sehen, dass diese Zahlen unterschiedlich sind, aber die Darstellung ist etwas unhandlich. Wenn wir sie binär betrachten (nun, hex, was äquivalent ist), erhalten wir ein klareres Bild:
Sie können sehen, dass sie sich um unterscheiden
2^-53
, was wichtig ist, da diese Zahl der kleinste darstellbare Unterschied zwischen zwei Zahlen ist, deren Wert nahe bei 1 liegt.Wir können für jeden Computer herausfinden, was diese kleinste darstellbare Zahl ist, indem wir in Rs Maschinenfeld schauen :
Sie können diese Tatsache verwenden, um eine Funktion "nahezu gleich" zu erstellen, mit der überprüft wird, ob die Differenz nahe an der kleinsten darstellbaren Zahl im Gleitkomma liegt. In der Tat existiert dies bereits :
all.equal
.Die Funktion all.equal überprüft also tatsächlich, ob der Unterschied zwischen den Zahlen die Quadratwurzel des kleinsten Unterschieds zwischen zwei Mantissen ist.
Dieser Algorithmus ist in der Nähe von extrem kleinen Zahlen, die Denormals genannt werden, etwas witzig, aber darüber müssen Sie sich keine Sorgen machen.
Vektoren vergleichen
Die obige Diskussion ging von einem Vergleich zweier Einzelwerte aus. In R gibt es keine Skalare, nur Vektoren und implizite Vektorisierung ist eine Stärke der Sprache. Für den elementweisen Vergleich des Werts von Vektoren gelten die vorherigen Prinzipien, die Implementierung unterscheidet sich jedoch geringfügig.
==
wird vektorisiert (führt einen elementweisen Vergleich durch), währendall.equal
die gesamten Vektoren als eine Einheit verglichen werden.Verwenden Sie die vorherigen Beispiele
==
gibt nicht das "erwartete" Ergebnis undall.equal
führt nicht elementweise durchVielmehr muss eine Version verwendet werden, die die beiden Vektoren durchläuft
Wenn eine funktionale Version davon gewünscht wird, kann sie geschrieben werden
was als gerecht bezeichnet werden kann
Anstatt
all.equal
noch mehr Funktionsaufrufe einzuschließen, können Sie alternativ einfach die relevanten Interna replizierenall.equal.numeric
und die implizite Vektorisierung verwenden:Dies ist der Ansatz von
dplyr::near
, der sich selbst als dokumentiertquelle
Wenn Sie zu Brians Kommentar hinzufügen (was der Grund ist), können Sie dies überwinden, indem Sie
all.equal
stattdessen Folgendes verwenden:Per Joshuas Warnung ist hier der aktualisierte Code (Danke Joshua):
quelle
all.equal
Wird nicht zurückgegeben,FALSE
wenn es Unterschiede gibt. Sie müssen es daher umschließen,isTRUE
wenn Sie es in einerif
Anweisung verwenden.Das ist hackisch, aber schnell:
quelle
all.equal(... tolerance)
Parameter jedoch verwenden.all.equal(0.147, 0.15, tolerance=0.05)
ist wahr.dplyr::near()
ist eine Option zum Testen, ob zwei Vektoren von Gleitkommazahlen gleich sind. Dies ist das Beispiel aus den Dokumenten :Die Funktion verfügt über einen eingebauten Toleranzparameter
tol = .Machine$double.eps^0.5
, der angepasst werden kann. Der Standardparameter ist der gleiche wie der Standardparameter fürall.equal()
.quelle
Ich hatte ein ähnliches Problem. Ich habe die folgende Lösung verwendet.
Ausgabe ungleicher Schnittintervalle basierend auf Optionen (Ziffern = 2):
Ausgabe gleicher Schnittintervalle basierend auf der Rundungsfunktion:
quelle
Verallgemeinerte Vergleiche ("<=", "> =", "=") in doppelter Präzisionsarithmetik:
Vergleichen von a <= b:
Vergleichen von a> = b:
Vergleich von a = b:
quelle