Rule of thumb to test the equality of two doubles in C#?

后端 未结 6 1919
忘掉有多难
忘掉有多难 2020-12-06 17:00

Let\'s say I have some code that does some floating point arithmetic and stores the values in doubles. Because some values can\'t be represented perfectly in binary, how do

6条回答
  •  一个人的身影
    2020-12-06 17:11

    Here is the implementation (comparing last bits of IEEE representation) mentioned in "Comparing Floating Point Numbers", by Bruce Dawsone, ported to C#.

    One could argue that Float.NaN != Float.NaN. This code will treat all the special IEEE float value (NaN, Inf, etc) as equal. For Unit Testing, this is probably what you want. For real production code, you probably shouldn't compare NaN or Inf to anything - you should throw an Exception or something smart.

    This is the same technique used by Google Test (gtest) for C++ as well.

    Gtest uses a default value of 4 for the maxUlps.

        public static bool AlmostEqual2sComplement(float A, float B, int maxUlps)
        {
            // Make sure maxUlps is non-negative and small enough that the
            // default NAN won't compare as equal to anything.
            if (!(maxUlps > 0 && maxUlps < 4 * 1024 * 1024)) throw new Exception("maxUlps is invalid");
    
            Int32 aInt = BitConverter.ToInt32(BitConverter.GetBytes(A),0);
            // Make aInt lexicographically ordered as a twos-complement int
            if (aInt < 0)
                aInt = Int32.MinValue + (-aInt);
            // Make bInt lexicographically ordered as a twos-complement int
            Int32 bInt = BitConverter.ToInt32(BitConverter.GetBytes(B), 0);
            if (bInt < 0)
                bInt = Int32.MinValue + (-bInt);
            Int64 intDiff = Math.Abs(aInt - bInt);
            if (intDiff <= maxUlps)
                return true;
            return false;
        }
        public static bool AlmostEqual2sComplement(double A, double B, int maxUlps)
        {
            // Make sure maxUlps is non-negative and small enough that the
            // default NAN won't compare as equal to anything.
            if (!(maxUlps > 0 && maxUlps < 4 * 1024 * 1024)) throw new Exception("maxUlps is invalid");
    
            Int64 aInt = BitConverter.ToInt64(BitConverter.GetBytes(A), 0);
            // Make aInt lexicographically ordered as a twos-complement int
            if (aInt < 0)
                aInt = Int64.MinValue + (- aInt);
            // Make bInt lexicographically ordered as a twos-complement int
            Int64 bInt = BitConverter.ToInt64(BitConverter.GetBytes(B), 0);
            if (bInt < 0)
                bInt = Int64.MinValue + (- bInt);
            Int64 intDiff = Math.Abs(aInt - bInt);
            if (intDiff <= maxUlps)
                return true;
            return false;
        }
    

提交回复
热议问题