671 Stimmen

Welches ist die effektivste Methode für einen Float- und Double-Vergleich?

Was wäre der effizienteste Weg, um zwei double oder zwei float Werte?

Dies einfach zu tun, ist nicht korrekt:

bool CompareDoubles1 (double A, double B)
{
   return A == B;
}

Aber so etwas wie:

bool CompareDoubles2 (double A, double B) 
{
   diff = A - B;
   return (diff < EPSILON) && (-diff < EPSILON);
}

Das scheint eine Verschwendung von Bearbeitungszeit zu sein.

Kennt jemand einen intelligenteren Float-Vergleicher?

-1voto

Daniel Laügt Punkte 988

Sie können nicht zwei double mit einem festen EPSILON . Je nach dem Wert von double , EPSILON variiert.

Ein besserer Doppelvergleich wäre:

bool same(double a, double b)
{
  return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
    && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}

-1voto

Murphy78 Punkte 49
/// testing whether two doubles are almost equal. We consider two doubles
/// equal if the difference is within the range [0, epsilon).
///
/// epsilon: a positive number (supposed to be small)
///
/// if either x or y is 0, then we are comparing the absolute difference to
/// epsilon.
/// if both x and y are non-zero, then we are comparing the relative difference
/// to epsilon.
bool almost_equal(double x, double y, double epsilon)
{
    double diff = x - y;
    if (x != 0 && y != 0){
        diff = diff/y; 
    }

    if (diff < epsilon && -1.0*diff < epsilon){
        return true;
    }
    return false;
}

Ich habe diese Funktion für mein kleines Projekt verwendet und sie funktioniert, aber beachten Sie Folgendes:

Fehler mit doppelter Genauigkeit können für eine Überraschung sorgen. Nehmen wir an, epsilon = 1,0e-6, dann sollten 1,0 und 1,000001 nach dem obigen Code NICHT als gleich angesehen werden, aber auf meinem Rechner sieht die Funktion sie als gleich an, weil 1,000001 nicht genau in ein Binärformat übersetzt werden kann, es ist wahrscheinlich 1,0000009xxx. Ich teste es mit 1,0 und 1,0000011 und erhalte diesmal das erwartete Ergebnis.

-2voto

Chameleon Punkte 1522

Ich schreibe dies für Java, aber vielleicht finden Sie es nützlich. Es verwendet Longs anstelle von Doubles, kümmert sich aber um NaNs, Subnormalen, etc.

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; }

Denken Sie daran, dass die Zahlen nach einer Reihe von Gleitkommaoperationen ganz anders aussehen können, als wir es erwarten. Es gibt keinen Code, um das zu beheben.

-2voto

Vijay Punkte 1951

Mein Weg mag nicht richtig sein, aber nützlich

Konvertieren Sie beide Fließkommazahlen in Zeichenketten und führen Sie dann einen Zeichenkettenvergleich durch.

bool IsFlaotEqual(float a, float b, int decimal)
{
    TCHAR form[50] = _T("");
    _stprintf(form, _T("%%.%df"), decimal);

    TCHAR a1[30] = _T(""), a2[30] = _T("");
    _stprintf(a1, form, a);
    _stprintf(a2, form, b);

    if( _tcscmp(a1, a2) == 0 )
        return true;

    return false;

}

Operator-Überlagerungen können auch durchgeführt werden

-3voto

Amir Saniyan Punkte 12082

Dies ist eine weitere Lösung mit Lambda:

#include <cmath>
#include <limits>

auto Compare = [](float a, float b, float epsilon = std::numeric_limits<float>::epsilon()){ return (std::fabs(a - b) <= epsilon); };

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