/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ namespace Standard { using System; using System.Diagnostics.CodeAnalysis; /// /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. /// Note that FP noise is a big problem and using any of these compare /// methods is not a complete solution, but rather the way to reduce /// the probability of repeating unnecessary work. /// internal static class DoubleUtilities { /// /// Epsilon - more or less random, more or less small number. /// private const double Epsilon = 0.00000153; /// /// AreClose returns whether or not two doubles are "close". That is, whether or /// not they are within epsilon of each other. /// 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. /// /// The first double to compare. /// The second double to compare. /// The result of the AreClose comparision. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool AreClose(double value1, double value2) { if (value1 == value2) { return true; } double delta = value1 - value2; return (delta < Epsilon) && (delta > -Epsilon); } /// /// LessThan returns whether or not the first double is less than the second double. /// That is, whether or not the first is strictly less than *and* not within epsilon of /// the other number. /// 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. /// /// The first double to compare. /// The second double to compare. /// The result of the LessThan comparision. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool LessThan(double value1, double value2) { return (value1 < value2) && !AreClose(value1, value2); } /// /// 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. /// 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. /// /// The first double to compare. /// The second double to compare. /// The result of the GreaterThan comparision. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool GreaterThan(double value1, double value2) { return (value1 > value2) && !AreClose(value1, value2); } /// /// LessThanOrClose returns whether or not the first double is less than or close to /// the second double. That is, whether or not the first is strictly less than or within /// epsilon of the other number. /// 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. /// /// The first double to compare. /// The second double to compare. /// The result of the LessThanOrClose comparision. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool LessThanOrClose(double value1, double value2) { return (value1 < value2) || AreClose(value1, value2); } /// /// GreaterThanOrClose returns whether or not the first double is greater than or close to /// the second double. That is, whether or not the first is strictly greater than or within /// epsilon of the other number. /// 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. /// /// The first double to compare. /// The second double to compare. /// The result of the GreaterThanOrClose comparision. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool GreaterThanOrClose(double value1, double value2) { return (value1 > value2) || AreClose(value1, value2); } /// /// Test to see if a double is a finite number (is not NaN or Infinity). /// /// The value to test. /// Whether or not the value is a finite number. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool IsFinite(double value) { return !double.IsNaN(value) && !double.IsInfinity(value); } /// /// Test to see if a double a valid size value (is finite and > 0). /// /// The value to test. /// Whether or not the value is a valid size value. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool IsValidSize(double value) { return IsFinite(value) && GreaterThanOrClose(value, 0); } } }