Compare two floats

前端 未结 5 1590
小蘑菇
小蘑菇 2020-12-03 01:39
#include 

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

I trie

相关标签:
5条回答
  • 2020-12-03 02:23

    Keep in mind that when float a = +2^(254-127) * 1.___22 zeros___1 and float b = +2^(254-127) * 1.___23 zeros___ then we expect abs(a-b) < epsilon but instead a - b = +2^(254-127-23) * 1.___23 zeros___ = 20282409603651670423947251286000 which is much bigger than epsilon...

    0 讨论(0)
  • 2020-12-03 02:24

    I write and test this code. It seems working.

    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; }
    
    • if any of the numbers is NaN, numbers are unequal.
    • if 2 numbers are identical, are equal. This is a fast initial check.
    • if both numbers are any of +0, -0 or subnormal, numbers are equal.
    • if numbers have different signs, numbers are unequal. This looks like a wrong approach if both numbers are almost 0 (but not ±0 or subnormals) with different signs. But what if you multiply these numbers with another? one result will be negative and the other positive. So we are strict and this is right.
    • if exponents have difference 2 or more, numbers are unequal, because one number is at least 2 times greater than the other.
    • if exponents have difference exactly 1, shift correctly the fraction from one of the numbers.
    • If difference of 2 fractions is small, numbers are equal.
    0 讨论(0)
  • 2020-12-03 02:36

    Look here: http://floating-point-gui.de/errors/comparison/

    Due to rounding errors, most floating-point numbers end up being slightly imprecise. As long as this imprecision stays small, it can usually be ignored. However, it also means that numbers expected to be equal (e.g. when calculating the same result through different correct methods) often differ slightly, and a simple equality test fails.

    And, of course, What Every Computer Scientist Should Know About Floating-Point Arithmetic

    0 讨论(0)
  • 2020-12-03 02:37

    First: there's no point in computing a boolean value (with the < operator) and then wrapping that in another boolean. Just write it like this:

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

    Second, it's possible that your epsilon itself isn't well-represented as a float, and thus doesn't look like what you expect. Try with a negative power of 2, such as 1/1048576 for instance.

    0 讨论(0)
  • 2020-12-03 02:38

    Alternatively, you could compare two integers instead. Just multiply your two floats by the desired precision and cast them to integers. Be sure to round up/down correctly. Here is what it looks like:

    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);
    }
    
    0 讨论(0)
提交回复
热议问题