namespace AIStudio.Wpf.DiagramDesigner { using System; public static class DoubleUtil { // Const values come from sdk\inc\crt\float.h #pragma warning disable SA1310 // Field names must not contain underscore // ReSharper disable once InconsistentNaming private const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ #pragma warning restore SA1310 // Field names must not contain underscore /// /// AreClose - Returns whether or not two doubles are "close". That is, whether or /// not they are within epsilon of each other. Note that this epsilon is proportional /// to the numbers themselves to that AreClose survives scalar multiplication. /// There are plenty of ways for this to return false even for numbers which /// are theoretically identical, so no code calling this should fail to work if this /// returns false. This is important enough to repeat: /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be /// used for optimizations *only*. /// /// /// bool - the result of the AreClose comparision. /// /// The first double to compare. /// The second double to compare. public static bool AreClose(double value1, double value2) { // in case they are Infinities (then epsilon check does not work) // ReSharper disable once CompareOfFloatsByEqualityOperator if (value1 == value2) { return true; } // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; var delta = value1 - value2; return (-eps < delta) && (eps > delta); } /// /// GreaterThan - Returns whether or not the first double is greater than the second double. /// That is, whether or not the first is strictly greater than *and* not within epsilon of /// the other number. Note that this epsilon is proportional to the numbers themselves /// to that AreClose survives scalar multiplication. Note, /// There are plenty of ways for this to return false even for numbers which /// are theoretically identical, so no code calling this should fail to work if this /// returns false. This is important enough to repeat: /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be /// used for optimizations *only*. /// /// /// bool - the result of the GreaterThan comparision. /// /// The first double to compare. /// The second double to compare. public static bool GreaterThan(double value1, double value2) { return (value1 > value2) && !AreClose(value1, value2); } } }