Wie gefährlich ist es, Gleitkommawerte zu vergleichen?


391

Ich kenne UIKitVerwendungen CGFloatwegen des auflösungsunabhängigen Koordinatensystems.

Aber jedes Mal , möchte ich , wenn beispielsweise überprüfen , frame.origin.xist 0es macht mich krank:

if (theView.frame.origin.x == 0) {
    // do important operation
}

Ist das nicht CGFloatanfällig für Fehlalarme bei einem Vergleich mit ==, <=, >=, <, >? Es ist ein Gleitkomma und sie haben Ungenauigkeitsprobleme: 0.0000000000041zum Beispiel.

Wird Objective-Cdies beim Vergleich intern behandelt oder kann es vorkommen, dass a, origin.xdas als Null lautet, nicht mit 0true verglichen wird ?

Antworten:


466

Erstens sind Gleitkommawerte in ihrem Verhalten nicht "zufällig". Ein genauer Vergleich kann und macht in vielen realen Anwendungen Sinn. Wenn Sie jedoch Gleitkomma verwenden möchten, müssen Sie sich dessen bewusst sein, wie es funktioniert. Wenn Sie davon ausgehen, dass Gleitkomma wie reelle Zahlen funktioniert, erhalten Sie Code, der schnell kaputt geht. Wenn Sie auf der Seite der Annahme von Gleitkommaergebnissen einen großen zufälligen Flaum haben (wie die meisten Antworten hier vermuten lassen), erhalten Sie Code, der auf den ersten Blick zu funktionieren scheint, aber am Ende große Fehler und Fälle mit gebrochenen Ecken aufweist.

Wenn Sie mit Gleitkomma programmieren möchten, sollten Sie zunächst Folgendes lesen:

Was jeder Informatiker über Gleitkomma-Arithmetik wissen sollte

Ja, lies alles. Wenn dies zu aufwändig ist, sollten Sie für Ihre Berechnungen Ganzzahlen / Fixpunkte verwenden, bis Sie Zeit zum Lesen haben. :-)

Nachdem dies gesagt wurde, sind die größten Probleme bei exakten Gleitkomma-Vergleichen folgende:

  1. Die Tatsache , dass viele Werte , die Sie in der Quelle schreiben können, oder lesen Sie in mit scanfoder strtod, existiert nicht als Gleitkommazahlen und geräuschlos auf die nächste Annäherung konvertiert werden. Dies ist, worüber die Antwort von Dämon9733 sprach.

  2. Die Tatsache, dass viele Ergebnisse gerundet werden, weil die Genauigkeit nicht ausreicht, um das tatsächliche Ergebnis darzustellen. Ein einfaches Beispiel, wo Sie dies sehen können, ist das Hinzufügen x = 0x1fffffeund y = 1als Floats. Hier xhat die Mantisse 24 Bit Genauigkeit (ok) und ynur 1 Bit, aber wenn Sie sie hinzufügen, befinden sich ihre Bits nicht an überlappenden Stellen, und das Ergebnis würde 25 Bit Genauigkeit erfordern. Stattdessen wird es gerundet (auf 0x2000000im Standardrundungsmodus).

  3. Die Tatsache, dass viele Ergebnisse gerundet werden, weil unendlich viele Stellen für den richtigen Wert benötigt werden. Dies beinhaltet sowohl rationale Ergebnisse wie 1/3 (die Sie von der Dezimalstelle kennen, wo es unendlich viele Stellen einnimmt) als auch 1/10 (das auch unendlich viele Stellen in binärer Form einnimmt, da 5 keine Zweierpotenz ist). sowie irrationale Ergebnisse wie die Quadratwurzel von allem, was kein perfektes Quadrat ist.

  4. Doppelte Rundung. Auf einigen Systemen (insbesondere x86) werden Gleitkommaausdrücke mit höherer Genauigkeit als ihre nominalen Typen ausgewertet. Dies bedeutet, dass Sie bei einer der oben genannten Rundungsarten zwei Rundungsschritte erhalten, zuerst eine Rundung des Ergebnisses auf den Typ mit höherer Genauigkeit und dann eine Rundung auf den endgültigen Typ. Betrachten Sie als Beispiel, was in Dezimalzahl passiert, wenn Sie 1,49 auf eine Ganzzahl (1) runden, und was passiert, wenn Sie es zuerst auf eine Dezimalstelle (1,5) runden und dann das Ergebnis auf eine Ganzzahl (2) runden. Dies ist tatsächlich einer der schlimmsten Bereiche, mit denen sich Gleitkommazahlen befassen müssen, da das Verhalten des Compilers (insbesondere bei fehlerhaften, nicht konformen Compilern wie GCC) nicht vorhersehbar ist.

  5. Transzendente Funktionen ( trig, exp, log, etc.) sind nicht korrekt gerundete Ergebnisse haben angegeben; Das Ergebnis wird nur so angegeben, dass es innerhalb einer Einheit an der letzten Stelle der Genauigkeit korrekt ist (normalerweise als 1ulp bezeichnet ).

Wenn Sie Gleitkomma-Code schreiben, müssen Sie berücksichtigen, was Sie mit den Zahlen tun, die dazu führen können, dass die Ergebnisse ungenau sind, und entsprechende Vergleiche anstellen. Oft ist es sinnvoll, mit einem "Epsilon" zu vergleichen, aber dieses Epsilon sollte auf der Größe der Zahlen basieren, die Sie vergleichen , und nicht auf einer absoluten Konstante. (In Fällen, in denen ein absolut konstantes Epsilon funktionieren würde, deutet dies stark darauf hin, dass der Festpunkt und nicht der Gleitkomma das richtige Werkzeug für den Job ist!)

Bearbeiten: Insbesondere sollte ein betragsbezogener Epsilon-Check ungefähr so ​​aussehen:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))

Wo FLT_EPSILONist die Konstante aus float.h(ersetzen Sie es durch DBL_EPSILONfür doubles oder LDBL_EPSILONfür long doubles) und Kist eine Konstante , die Sie so wählen , dass der akkumulierte Fehler Ihrer Berechnungen auf jeden Fall begrenzt ist durch KEinheiten in den letzten Platz (und wenn Sie nicht sicher sind , haben Sie den Fehler gebundene Berechnung richtig, machen Sie Kein paar Mal größer als das, was Ihre Berechnungen sagen, dass es sein sollte).

Beachten Sie schließlich, dass bei Verwendung dieser Funktion möglicherweise besondere Sorgfalt nahe Null erforderlich ist, da FLT_EPSILONdies für Denormale keinen Sinn ergibt. Eine schnelle Lösung wäre, es zu machen:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)

und ebenfalls ersetzen, DBL_MINwenn Doppel verwendet werden.


25
fabs(x+y)ist problematisch, wenn xund y(kann) ein anderes Vorzeichen haben. Trotzdem eine gute Antwort gegen die Flut von Frachtkult-Vergleichen.
Daniel Fischer

27
Wenn xund yhaben ein anderes Vorzeichen, ist das kein Problem. Die rechte Seite wird "zu klein" sein, aber da xund yunterschiedliche Vorzeichen haben, sollten sie sowieso nicht gleich vergleichen. (Es sei denn, sie sind so klein, dass sie denormal sind, aber dann fängt der zweite Fall es auf)
R .. GitHub STOP HELPING ICE

4
Ich bin gespannt auf Ihre Aussage: "Besonders für fehlerhafte, nicht konforme Compiler wie GCC". Ist GCC wirklich fehlerhaft und auch nicht konform?
Nicolás Ozimica

3
Da die Frage mit iOS gekennzeichnet ist, ist es erwähnenswert, dass Apples Compiler (sowohl Clang- als auch Apples GCC-Builds) immer FLT_EVAL_METHOD = 0 verwendet haben und versuchen, absolut streng zu sein, um keine übermäßige Genauigkeit zu gewährleisten. Wenn Sie Verstöße dagegen feststellen, reichen Sie bitte Fehlerberichte ein.
Stephen Canon

17
"Erstens sind Gleitkommawerte in ihrem Verhalten nicht" zufällig ". Ein genauer Vergleich kann und macht in vielen realen Anwendungen Sinn." - Nur zwei Sätze und bereits +1 verdient! Dies ist eine der störendsten Fehleinschätzungen, die Menschen bei der Arbeit mit Gleitkommazahlen machen.
Christian Rau

36

Da 0 genau als IEEE754-Gleitkommazahl darstellbar ist (oder eine andere Implementierung von fp-Zahlen verwendet, mit denen ich jemals gearbeitet habe), ist ein Vergleich mit 0 wahrscheinlich sicher. Sie könnten jedoch gebissen werden, wenn Ihr Programm einen Wert berechnet (z. B. theView.frame.origin.x), von dem Sie Grund zu der Annahme haben, dass er 0 sein sollte, dessen Berechnung jedoch nicht garantieren kann, dass er 0 ist.

Um ein wenig zu verdeutlichen, eine Berechnung wie:

areal = 0.0

wird (es sei denn, Ihre Sprache oder Ihr System ist fehlerhaft) einen Wert erstellen, so dass (areal == 0.0) true zurückgibt, aber eine andere Berechnung wie

areal = 1.386 - 2.1*(0.66)

nicht dürfen.

Wenn Sie sich sicher sein können, dass Ihre Berechnungen Werte ergeben, die 0 sind (und nicht nur Werte, die 0 sein sollten), können Sie fp-Werte mit 0 vergleichen. Wenn Sie sich nicht im erforderlichen Maße versichern können Halten Sie sich am besten an den üblichen Ansatz der „tolerierten Gleichstellung“.

Im schlimmsten Fall kann der unachtsame Vergleich von fp-Werten äußerst gefährlich sein: Denken Sie an Avionik, Waffenführung, Kraftwerksbetrieb, Fahrzeugnavigation und fast jede Anwendung, bei der die Berechnung auf die reale Welt trifft.

Für Angry Birds nicht so gefährlich.


11
Eigentlich 1.30 - 2*(0.65)ist ein perfektes Beispiel für einen Ausdruck, der offensichtlich auf 0,0 bewertet , wenn Ihr Compiler implementiert IEEE 754, weil die doppelt als dargestellt 0.65und 1.30haben die gleichen Mantissen und Multiplikation mit zwei ist offensichtlich genau.
Pascal Cuoq

7
Ich bekomme immer noch Wiederholungen von diesem, also habe ich das zweite Beispiel-Snippet geändert.
High Performance Mark

22

Ich möchte eine etwas andere Antwort geben als die anderen. Sie eignen sich hervorragend zur Beantwortung Ihrer Frage, aber wahrscheinlich nicht für das, was Sie wissen müssen oder was Ihr eigentliches Problem ist.

Gleitkomma in Grafiken ist in Ordnung! Es ist jedoch fast nicht erforderlich, Floats direkt zu vergleichen. Warum sollten Sie das tun müssen? Grafik verwendet Floats, um Intervalle zu definieren. Und zu vergleichen, ob ein Float innerhalb eines Intervalls liegt, das auch durch Floats definiert ist, ist immer gut definiert und muss lediglich konsistent, nicht genau oder präzise sein! Solange ein Pixel (das auch ein Intervall ist!) Zugewiesen werden kann, sind alle Grafikanforderungen erfüllt.

Wenn Sie also testen möchten, ob Ihr Punkt außerhalb eines Bereichs von [0..width [liegt, ist dies in Ordnung. Stellen Sie einfach sicher, dass Sie die Inklusion konsistent definieren. Zum Beispiel immer innerhalb definieren ist (x> = 0 && x <Breite). Gleiches gilt für Kreuzungs- oder Treffertests.

Wenn Sie jedoch eine Grafikkoordinate als eine Art Flag missbrauchen, z. B. um festzustellen, ob ein Fenster angedockt ist oder nicht, sollten Sie dies nicht tun. Verwenden Sie stattdessen ein boolesches Flag, das von der Grafikpräsentationsebene getrennt ist.


13

Der Vergleich mit Null kann eine sichere Operation sein, solange die Null kein berechneter Wert war (wie in einer obigen Antwort angegeben). Der Grund dafür ist, dass Null eine perfekt darstellbare Zahl im Gleitkomma ist.

Wenn Sie perfekt darstellbare Werte sprechen, erhalten Sie 24 Bit Reichweite in einem Zweierpotenzbegriff (einfache Genauigkeit). 1, 2, 4 sind also perfekt darstellbar, ebenso wie .5, .25 und .125. Solange alle wichtigen Bits in 24 Bits vorliegen, sind Sie golden. So kann 10.625 präzise dargestellt werden.

Das ist toll, fällt aber unter Druck schnell auseinander. Zwei Szenarien fallen mir ein: 1) Wenn es sich um eine Berechnung handelt. Vertraue nicht, dass sqrt (3) * sqrt (3) == 3. Es wird einfach nicht so sein. Und es wird wahrscheinlich nicht innerhalb eines Epsilons sein, wie einige der anderen Antworten vermuten lassen. 2) Wenn ein Non-Power-of-2 (NPOT) beteiligt ist. Es mag seltsam klingen, aber 0.1 ist eine unendliche Reihe in Binärform, und daher ist jede Berechnung mit einer solchen Zahl von Anfang an ungenau.

(Oh, und die ursprüngliche Frage erwähnte Vergleiche mit Null. Vergessen Sie nicht, dass -0,0 auch ein perfekt gültiger Gleitkommawert ist.)


11

[Die 'richtige Antwort' beschönigt die Auswahl K. Die Auswahl erfolgt Kgenauso ad-hoc wie die Auswahl, VISIBLE_SHIFTaber die Auswahl Kist weniger offensichtlich, da sie im Gegensatz VISIBLE_SHIFTzu keiner Anzeigeeigenschaft basiert. Wählen Sie also Ihr Gift - wählen Sie Koder wählen Sie VISIBLE_SHIFT. Diese Antwort befürwortet die Auswahl VISIBLE_SHIFTund zeigt dann die Schwierigkeit bei der Auswahl K]

Gerade wegen Rundungsfehlern sollten Sie für logische Operationen keinen Vergleich von 'exakten' Werten verwenden. In Ihrem speziellen Fall einer Position auf einem visuellen Display kann es unmöglich sein, ob die Position 0,0 oder 0,0000000003 beträgt - der Unterschied ist für das Auge unsichtbar. Ihre Logik sollte also ungefähr so ​​aussehen:

#define VISIBLE_SHIFT    0.0001        // for example
if (fabs(theView.frame.origin.x) < VISIBLE_SHIFT) { /* ... */ }

Letztendlich hängt "für das Auge unsichtbar" jedoch von Ihren Anzeigeeigenschaften ab. Wenn Sie die Anzeige nach oben verschieben können (sollten Sie in der Lage sein); Wählen Sie dann, ob Sie VISIBLE_SHIFTein Bruchteil dieser Obergrenze sein möchten.

Nun beruht die „richtige Antwort“ darauf. KLassen Sie uns also die Auswahl untersuchen K. Die 'richtige Antwort' oben lautet:

K ist eine Konstante, die Sie so wählen, dass der akkumulierte Fehler Ihrer Berechnungen definitiv an letzter Stelle durch K Einheiten begrenzt wird (und wenn Sie nicht sicher sind, ob Sie die fehlergebundene Berechnung richtig ausgeführt haben, machen Sie K ein paar Mal größer als Ihre Berechnungen sag es sollte sein)

Also brauchen wir K. Wenn es Kschwieriger und weniger intuitiv ist, meine zu finden VISIBLE_SHIFT, entscheiden Sie, was für Sie funktioniert. Um dies herauszufinden, werden Kwir ein Testprogramm schreiben, das eine Reihe von KWerten betrachtet, damit wir sehen können, wie es sich verhält. KSollte offensichtlich sein, wie man wählt , wenn die "richtige Antwort" verwendbar ist. Nein?

Wir werden als "richtige Antwort" Details verwenden:

if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)

Probieren wir einfach alle Werte von K aus:

#include <math.h>
#include <float.h>
#include <stdio.h>

void main (void)
{
  double x = 1e-13;
  double y = 0.0;

  double K = 1e22;
  int i = 0;

  for (; i < 32; i++, K = K/10.0)
    {
      printf ("K:%40.16lf -> ", K);

      if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
        printf ("YES\n");
      else
        printf ("NO\n");
    }
}
ebg@ebg$ gcc -o test test.c
ebg@ebg$ ./test
K:10000000000000000000000.0000000000000000 -> YES
K: 1000000000000000000000.0000000000000000 -> YES
K:  100000000000000000000.0000000000000000 -> YES
K:   10000000000000000000.0000000000000000 -> YES
K:    1000000000000000000.0000000000000000 -> YES
K:     100000000000000000.0000000000000000 -> YES
K:      10000000000000000.0000000000000000 -> YES
K:       1000000000000000.0000000000000000 -> NO
K:        100000000000000.0000000000000000 -> NO
K:         10000000000000.0000000000000000 -> NO
K:          1000000000000.0000000000000000 -> NO
K:           100000000000.0000000000000000 -> NO
K:            10000000000.0000000000000000 -> NO
K:             1000000000.0000000000000000 -> NO
K:              100000000.0000000000000000 -> NO
K:               10000000.0000000000000000 -> NO
K:                1000000.0000000000000000 -> NO
K:                 100000.0000000000000000 -> NO
K:                  10000.0000000000000000 -> NO
K:                   1000.0000000000000000 -> NO
K:                    100.0000000000000000 -> NO
K:                     10.0000000000000000 -> NO
K:                      1.0000000000000000 -> NO
K:                      0.1000000000000000 -> NO
K:                      0.0100000000000000 -> NO
K:                      0.0010000000000000 -> NO
K:                      0.0001000000000000 -> NO
K:                      0.0000100000000000 -> NO
K:                      0.0000010000000000 -> NO
K:                      0.0000001000000000 -> NO
K:                      0.0000000100000000 -> NO
K:                      0.0000000010000000 -> NO

Ah, also sollte K 1e16 oder größer sein, wenn 1e-13 'Null' sein soll.

Ich würde also sagen, Sie haben zwei Möglichkeiten:

  1. Führen Sie eine einfache Epsilon-Berechnung durch, indem Sie Ihr technisches Urteil für den Wert von 'Epsilon' verwenden, wie ich vorgeschlagen habe. Wenn Sie Grafiken erstellen und "Null" eine "sichtbare Änderung" darstellt, überprüfen Sie Ihre visuellen Elemente (Bilder usw.) und beurteilen Sie, was Epsilon sein kann.
  2. Versuchen Sie keine Gleitkommaberechnungen, bis Sie die Referenz der Antwort ohne Frachtkult gelesen haben (und dabei Ihren Doktortitel erhalten haben) und wählen Sie dann anhand Ihres nicht intuitiven Urteils aus K.

10
Ein Aspekt der Auflösungsunabhängigkeit ist, dass Sie nicht sicher sagen können, was eine "sichtbare Verschiebung" zur Kompilierungszeit ist. Was auf einem Super-HD-Bildschirm unsichtbar ist, kann auf einem winzigen Bildschirm sehr offensichtlich sein. Man sollte es zumindest zu einer Funktion der Bildschirmgröße machen. Oder nennen Sie es etwas anderes.
Romain

1
Zumindest die Auswahl von "sichtbare Verschiebung" basiert jedoch auf leicht verständlichen Anzeige- (oder Rahmen-) Eigenschaften - im Gegensatz zu den <richtigen Antworten>, Kdie schwierig und nicht intuitiv auszuwählen sind.
GoZoner

5

Die richtige Frage: Wie vergleicht man Punkte in Cocoa Touch?

Die richtige Antwort: CGPointEqualToPoint ().

Eine andere Frage: Sind zwei berechnete Werte gleich?

Die Antwort hier gepostet: Sie sind nicht.

Wie kann man überprüfen, ob sie in der Nähe sind? Wenn Sie überprüfen möchten, ob sie nahe beieinander liegen, verwenden Sie CGPointEqualToPoint () nicht. Überprüfen Sie jedoch nicht, ob sie in der Nähe sind. Tun Sie etwas, das in der realen Welt Sinn macht, z. B. zu überprüfen, ob sich ein Punkt jenseits einer Linie befindet oder ob sich ein Punkt innerhalb einer Kugel befindet.


4

Als ich das letzte Mal den C-Standard überprüfte, war es nicht erforderlich, dass Gleitkommaoperationen auf Doppelwerten (64 Bit insgesamt, 53 Bit Mantisse) mit mehr als dieser Genauigkeit genau waren. Einige Hardwarekomponenten können jedoch die Operationen in Registern mit größerer Genauigkeit ausführen, und die Anforderung wurde dahingehend interpretiert, dass keine Anforderung zum Löschen von Bits niedrigerer Ordnung (über die Genauigkeit der in die Register geladenen Zahlen hinaus) besteht. Sie könnten also unerwartete Ergebnisse solcher Vergleiche erhalten, je nachdem, was in den Registern von dem übrig geblieben ist, der zuletzt dort geschlafen hat.

Das heißt, und trotz meiner Bemühungen, es zu löschen, wann immer ich es sehe, hat das Outfit, in dem ich arbeite, viel C-Code, der mit gcc kompiliert und unter Linux ausgeführt wird, und wir haben seit langer Zeit keine dieser unerwarteten Ergebnisse mehr bemerkt . Ich habe keine Ahnung, ob dies daran liegt, dass gcc die niederwertigen Bits für uns löscht, die 80-Bit-Register für diese Operationen auf modernen Computern nicht verwendet werden, der Standard geändert wurde oder was. Ich würde gerne wissen, ob jemand Kapitel und Verse zitieren kann.


1

Sie können einen solchen Code verwenden, um float mit null zu vergleichen:

if ((int)(theView.frame.origin.x * 100) == 0) {
    // do important operation
}

Dies wird mit einer Genauigkeit von 0,1 verglichen, die in diesem Fall für CGFloat ausreicht.


Das Casting intohne Versicherung theView.frame.origin.xliegt in / nahe diesem Bereich von intführt zu undefiniertem Verhalten (UB) - oder in diesem Fall 1/100 des Bereichs von int.
chux

Es gibt absolut keinen Grund, in eine solche Ganzzahl umzuwandeln. Wie Chux sagte, besteht für UB das Potenzial von Werten außerhalb des Bereichs. Bei einigen Architekturen ist dies erheblich langsamer als nur die Berechnung im Gleitkomma. Wenn Sie mit 100 multiplizieren, wird dies mit einer Genauigkeit von 0,01 und nicht mit 0,1 verglichen.
Sneftel

0
-(BOOL)isFloatEqual:(CGFloat)firstValue secondValue:(CGFloat)secondValue{

BOOL isEqual = NO;

NSNumber *firstValueNumber = [NSNumber numberWithDouble:firstValue];
NSNumber *secondValueNumber = [NSNumber numberWithDouble:secondValue];

isEqual = [firstValueNumber isEqualToNumber:secondValueNumber];

return isEqual;

}}


0

Ich verwende die folgende Vergleichsfunktion, um eine Anzahl von Dezimalstellen zu vergleichen:

bool compare(const double value1, const double value2, const int precision)
{
    int64_t magnitude = static_cast<int64_t>(std::pow(10, precision));
    int64_t intValue1 = static_cast<int64_t>(value1 * magnitude);
    int64_t intValue2 = static_cast<int64_t>(value2 * magnitude);
    return intValue1 == intValue2;
}

// Compare 9 decimal places:
if (compare(theView.frame.origin.x, 0, 9)) {
    // do important operation
}

-6

Ich würde sagen, das Richtige ist, jede Zahl als Objekt zu deklarieren und dann drei Dinge in diesem Objekt zu definieren: 1) einen Gleichheitsoperator. 2) eine setAcceptableDifference-Methode. 3) der Wert selbst. Der Gleichheitsoperator gibt true zurück, wenn die absolute Differenz zweier Werte kleiner als der als akzeptabel festgelegte Wert ist.

Sie können das Objekt entsprechend dem Problem in Unterklassen unterteilen. Beispielsweise können runde Metallstangen zwischen 1 und 2 Zoll als gleich groß angesehen werden, wenn sich ihre Durchmesser um weniger als 0,0001 Zoll unterscheiden. Sie würden also setAcceptableDifference mit dem Parameter 0,0001 aufrufen und dann den Gleichheitsoperator mit Sicherheit verwenden.


1
Dies ist keine gute Antwort. Erstens tut die ganze "Objektsache" überhaupt nichts, um Ihr Problem zu lösen. Und zweitens ist Ihre tatsächliche Implementierung von "Gleichheit" tatsächlich nicht die richtige.
Tom Swirly

3
Tom, vielleicht denkst du noch einmal über das "Objekt" nach. Bei reellen Zahlen, die mit hoher Präzision dargestellt werden, kommt es selten zu Gleichheit. Aber die Vorstellung von Gleichheit kann zugeschnitten werden, wenn sie zu Ihnen passt. Es wäre schöner, wenn es einen überschreibbaren "ungefähr gleichen" Operator gäbe, aber es gibt keinen.
John White
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.