Vergleichen Sie zwei Schwimmer

Lesezeit: 5 Minuten

Benutzer-Avatar
Kate

#include <stdbool.h>

bool Equality(double a, double b, double epsilon)
{
  if (fabs(a-b) < epsilon) return true;
  return false;
}

Ich habe diese Methode ausprobiert, um zwei Doubles zu vergleichen, aber ich bekomme immer Probleme, da ich nicht weiß, wie ich die auswählen soll epsiloneigentlich möchte ich kleine Zahlen (6 6 Nachkommastellen) vergleichen 0,000001. Ich habe es mit einigen Nummern versucht, manchmal bekomme ich es hin 0.000001 != 0.000001 und manchmal 0.000001 == 0.000002
Gibt es eine andere Methode als den Vergleich mit dem Epsilon?

Mein Ziel ist es, zwei Doubles zu vergleichen (die in meinem Fall die Zeit darstellen). Die Variable t, die die Zeit in Millisekunden darstellt, ist ein Double. Es wird durch eine andere Funktion 0,000001, dann 0,000002 usw. erhöht. Jedes Mal, wenn sich t ändert, möchte ich überprüfen, ob es gleich einer anderen Variablen vom Typ Double tt ist, falls tt == t, habe ich einige Anweisungen auszuführen.
Danke für Ihre Hilfe

  • “Epsilon”, nicht Epselon. de.wikipedia.org/wiki/Epsilon

    – Roddy

    13. Mai 2011 um 8:36 Uhr


  • Weder 0,000001 noch 0,000002 haben eine exakte Darstellung als Fließkomma, beide sind unendliche binäre Brüche mit wiederkehrenden Dezimalstellen. Darüber hinaus ist fabs(ab) anfällig für katastrophale Stornierungen.

    – Günther Piez

    13. Mai 2011 um 8:48 Uhr


  • Wenn Sie nicht wissen, worum es geht, können Sie zumindest das erste Problem vermeiden, indem Sie ein Epsilon verwenden, das genau als Float dargestellt werden kann, wie 0,00000095367431640625, was 2^-20 ist und nahe an 10^-6 liegt Sie wollen

    – Günther Piez

    13. Mai 2011 um 8:53 Uhr

  • Warum benutzt du float an erster Stelle? Vorziehen double ohne ein sehr stark für andere Fließkommatypen. Natürlich bleibt Ihre Frage, ob es floats oder doubles.

    – pmg

    13. Mai 2011 um 9:05 Uhr

  • mögliches Duplikat von Effektivster Weg für Gleitkomma- und Doppelvergleich

    – Roddy

    26. Juni 2013 um 10:32 Uhr

Benutzer-Avatar
Roddy

Schau hier: http://floating-point-gui.de/errors/comparison/

Aufgrund von Rundungsfehlern sind die meisten Fließkommazahlen etwas ungenau. Solange diese Ungenauigkeit gering bleibt, kann sie in der Regel vernachlässigt werden. Es bedeutet aber auch, dass erwartete Gleichheiten (z. B. bei der Berechnung des gleichen Ergebnisses mit unterschiedlichen korrekten Methoden) oft leicht voneinander abweichen und ein einfacher Gleichheitstest fehlschlägt.

Und natürlich, Was jeder Informatiker über Gleitkommaarithmetik wissen sollte

Erstens: Es macht keinen Sinn, einen booleschen Wert zu berechnen (mit der < Operator) und dann in einen anderen booleschen Wert einpacken. Schreib es einfach so:

bool Equality(float a, float b, float epsilon)
{
  return fabs(a - b) < epsilon;
}

Zweitens ist es möglich, dass Ihr Epsilon selbst nicht gut als dargestellt wird float, und sieht daher nicht so aus, wie Sie es erwarten. Versuchen Sie es mit einer negativen Potenz von 2, z. B. 1/1048576.

  • Danke für deine Antwort. Wenn eps = 0,000001, bekomme ich ein falsches Ergebnis (0,000001 == 0,000002), aber wenn ich etwas wie 1/1048576 verwende, ist das Ergebnis immer != (auch wenn ich 0,000001 mit 0,000001 vergleiche) 🙁

    – Kate

    13. Mai 2011 um 8:52 Uhr


Alternativ könnten Sie stattdessen zwei ganze Zahlen vergleichen. Multiplizieren Sie einfach Ihre beiden Floats mit der gewünschten Genauigkeit und wandeln Sie sie in Ganzzahlen um. Achten Sie darauf, dass Sie richtig auf-/abrunden. So sieht es aus:

BOOL floatcmp(float float1, float float2, unsigned int precision){
   int int1, int2;

   if (float1 > 0)
      int1 = (int)(float1 * precision + .5);
   else
      int1 = (int)(float1 * precision - .5);

   if (float2 > 0)
      int2 = (int)(float2 * precision + .5);
   else
      int2 = (int)(float2 * precision - .5);

   return (int1 == int2);
}

Benutzer-Avatar
Chamäleon

Denken Sie daran, wann float a = +2^(254-127) * 1.___22 zeros___1 und float b = +2^(254-127) * 1.___23 zeros___ dann erwarten wir abs(a-b) < epsilon aber stattdessen a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000 das ist viel größer als epsilon …

Benutzer-Avatar
Chamäleon

Ich schreibe und teste diesen Code. Es scheint zu funktionieren.

public static boolean equal(double a, double b) {
    final long fm = 0xFFFFFFFFFFFFFL;       // fraction mask
    final long sm = 0x8000000000000000L;    // sign mask
    final long cm = 0x8000000000000L;       // most significant decimal bit mask
    long c = Double.doubleToLongBits(a), d = Double.doubleToLongBits(b);        
    int ea = (int) (c >> 52 & 2047), eb = (int) (d >> 52 & 2047);
    if (ea == 2047 && (c & fm) != 0 || eb == 2047 && (d & fm) != 0) return false;   // NaN 
    if (c == d) return true;                            // identical - fast check
    if (ea == 0 && eb == 0) return true;                // ±0 or subnormals
    if ((c & sm) != (d & sm)) return false;             // different signs
    if (abs(ea - eb) > 1) return false;                 // b > 2*a or a > 2*b
    d <<= 12; c <<= 12;
    if (ea < eb) c = c >> 1 | sm;
    else if (ea > eb) d = d >> 1 | sm;
    c -= d;
    return c < 65536 && c > -65536;     // don't use abs(), because:
    // There is a posibility c=0x8000000000000000 which cannot be converted to positive
}
public static boolean zero(double a) { return (Double.doubleToLongBits(a) >> 52 & 2047) < 3; }
  • Wenn eine der Zahlen NaN ist, sind die Zahlen ungleich.
  • wenn 2 Zahlen identisch sind, sind gleich. Dies ist eine schnelle Erstprüfung.
  • wenn beide Zahlen +0, -0 oder subnormal sind, sind die Zahlen gleich.
  • Wenn Zahlen unterschiedliche Vorzeichen haben, sind Zahlen ungleich. Dies sieht nach einem falschen Ansatz aus, wenn beide Zahlen mit unterschiedlichen Vorzeichen fast 0 (aber nicht ±0 oder subnormal) sind. Aber was ist, wenn Sie diese Zahlen mit einer anderen multiplizieren? ein Ergebnis wird negativ und das andere positiv sein. Also sind wir streng und das ist richtig.
  • Wenn die Exponenten eine Differenz von 2 oder mehr haben, sind Zahlen ungleich, weil eine Zahl mindestens zweimal größer ist als die andere.
  • Wenn Exponenten genau 1 Differenz haben, verschieben Sie den Bruch von einer der Zahlen richtig.
  • Wenn die Differenz von 2 Brüchen klein ist, sind die Zahlen gleich.

1204890cookie-checkVergleichen Sie zwei Schwimmer

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy