/// <summary> /// Compares two floating point values within a specified tolerance in ULPs. /// </summary> /// <param name="x">One floating point value to be compared.</param> /// <param name="y">Other floating point value to be compared.</param> /// <param name="tolerance">The tolerance for equality in terms of ULPs.</param> /// <param name="difference">The difference between the values in terms of ULPs.</param> /// <returns>0 if <paramref name="x"/> = <paramref name="y"/> ± <paramref name="tolerance"/> ULPs; +1 if x > y + tolerance ULPs; -1 if x < y - tolerance ULPs.</returns> /// <remarks> /// <list> /// <item> 0 if x = y ± tolerance ULPs</item> /// <item>+1 if x > y + tolerance ULPs</item> /// <item>-1 if x < y - tolerance ULPs</item> /// </list> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="tolerance"/> is negative or in excess of 2<sup>51</sup> (the limit of the significand in a double-precision floating point value).</exception> public static int Compare(double x, double y, long tolerance, out long difference) { // Make sure tolerance is non-negative and small enough that the // default NAN won't compare as equal to anything. const long maxSignificand = 2L * 1024 * 1024 * 1024 * 1024 * 1024; // double-precision values has a 51-bit significand if (tolerance < 0 || tolerance >= maxSignificand) { throw new ArgumentOutOfRangeException("tolerance", "Tolerance must be in the range [0,2\u2075\u00B9)"); } // Reinterpret double bits as sign-magnitude long integers. long xi = DoubleBitReinterpreter.Convert(x); long yi = DoubleBitReinterpreter.Convert(y); // Convert from sign-magnitude to two's complement form, // by subtracting from 0x8000000000000000. if (xi < 0) { xi = long.MinValue - xi; } if (yi < 0) { yi = long.MinValue - yi; } // How many epsilons apart? difference = xi - yi; // Is the difference outside our tolerance? if (xi > yi + tolerance) { return(+1); } if (xi < yi - tolerance) { return(-1); } else { return(0); } }
internal static double Convert(long value) { return(DoubleBitReinterpreter.Convert(value)); }
internal static long Convert(double value) { return(DoubleBitReinterpreter.Convert(value)); }