Schnelle Rundungsfunktion



  • Was spricht dann dagegen, einfach die Differenz zu bilden?

    auto d1 = 6.12349684731;
    auto d2 = 6.12348874662;
    std::abs(d1-d2)
    (double) 8.10069e-06
    std::abs(d1-d2) < 0.0001
    (bool) true
    


  • Die Genauigkeit hängt nicht von den Nachkommastellen1 ab, sondern von den signifikanten Stellen.

    1Bei der Exponentialschreibweise kann man die Nachkommstellen betrachten.


  • Mod

    Das was DirkB sagt. Aber noch mit der Ergänzung, dass auch das nicht reicht. Die dumme 0 macht alles kaputt und es gibt noch weitere mögliche Komplikationen. Das ganze Thema ist schwierig (und zwar sehr viel schwieriger, als der TE denkt!) und es gibt leider keine zufriedenstellenden Lösungen, die wirklich alle Fälle abdecken. Siehe hier für eine Abhandlung:
    https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

    Noch eine interessante Lösung technischer Art: Nach IEEE 754 ist die Integer-Repräsentation von Fließkommazahlen geordnet. Wenn man sich also darauf verlassen kann, dass die Maschine diesen Standard benutzt (kann man zu 99.9999%) und man hat Zugriff auf diese Repräsentation (in C++ kein Problem), dann kann man sich ausrechnen, um wie viele float-"Schritte" sich zwei Werte unterscheiden und danach ein Vergleichskriterium bauen. Das Problem mit der 0 bleibt jedoch bestehen 😞



  • Morom schrieb:

    Wenn z.B. zwei double-Werte 6.12349684731 und 6.12348874662 vorkommen, so sind diese nicht gleich. Jetzt benötige ich aber nur eine Genauigkeit von 4 Nachkommastellen, also runde ich die beiden Werte nach 6.1235 und 6.1235 -> sie sind gleich.

    nach dem Verfahren wären 6.12346 und 6.12354 gleich, aber 6.12346 und 6.12344 wären nicht gleich, obwohl ihre Differenz nur 1/4 von der Differenz des ersten Zahlenpaars ausmacht.



  • Vergleiche mit begrenzter Genauigkeit

    Wie wärs damit?

    bool is_almost_equal(double a, double b, double prec=0.0001)
    {
        return abs(a-b) <= prec; // ?
    }
    

  • Mod

    Ist halt die Frage, ob 1e-7 und 1e-17 wirklich als gleich gelten sollen, obwohl 10 Größenordnungen (und ca 1.5e17 potentielle double-Werte) dazwischen liegen.

    Oder ob 1.00001 und 1000002 wirklich als gleich gelten sollen, während 100000000000001 und 100000000000002 als verschieden gelten (obwohl da nur 64 andere Werte zwischen gehen!).



  • Ja, das ist alles nicht so einfach.
    Ich weiss auch gar nicht ob man überhaupt eine richtig schnelle (und gleichzeitig schlaue) Epsilon-Equals Funktion machen kann. Also z.B. eine wo Epsilon ein vielfaches der "Unit in the Last Place" (ULP) ist.
    Wenn's auch langsam sein darf, dann ist es nicht so schwer. ULP der grösseren Zahl ermitteln, mit Konstante multiplizieren, und dann gucken ob die Differenz der beiden Zahlen betragsmässig kleiner ist.

    @Morom
    Muss dein Test auf "Gleichheit" transitiv sein?
    Wenn nein, dann bietet sich eine Epsilon-Equals Funktion mit manuellem Epsilon an, so wie wob bzw. HarteWare es vorgeschlagen haben.

    Und wenn du eine transitive Funktion brauchst, dann ist vermutlich Runden eh die beste Lösung. Nur würde ich, wenns geht, auf binäre Stellen runden und nicht auf dezimale.


  • Mod

    hustbaer schrieb:

    Ja, das ist alles nicht so einfach.
    Ich weiss auch gar nicht ob man überhaupt eine richtig schnelle (und gleichzeitig schlaue) Epsilon-Equals Funktion machen kann. Also z.B. eine wo Epsilon ein vielfaches der "Unit in the Last Place" (ULP) ist.
    Wenn's auch langsam sein darf, dann ist es nicht so schwer. ULP der grösseren Zahl ermitteln, mit Konstante multiplizieren, und dann gucken ob die Differenz der beiden Zahlen betragsmässig kleiner ist.

    Die schnelle Methode dafür habe ich doch schon genannt. Nach int casten, Differenz bilden, mit Vorgabe vergleichen. Funktioniert auf jeder IEEE 754 Maschine. Eventuell noch Sonderbehandlung für NaN, inf, usw. einführen.

    Problem ist halt, dass solch ein flexibler epsilon-Vergleich nicht mit der häufig gewünschten Funktionalität kompatibel ist, unter einer gewissen Schranke alles als 0 anzusehen. Da muss man dann wieder eine Sonderprüfung einbauen.



  • hustbaer schrieb:

    so wie wob bzw. HarteWare es vorgeschlagen haben.

    Ach, ich Blindfisch! Habe diesen kleinen Code-Snippet voll übersehen. War natürlich nicht meine Absicht alles zwei Mal zu sagen.



  • @SeppJ
    Womit wir wieder beim Thema "scheiss strict aliasing" wären 😃


Anmelden zum Antworten