DoubleUtil.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*************************************************************************************
  2. Extended WPF Toolkit
  3. Copyright (C) 2007-2013 Xceed Software Inc.
  4. This program is provided to you under the terms of the Microsoft Public
  5. License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
  6. For more features, controls, and fast professional support,
  7. pick up the Plus Edition at http://xceed.com/wpf_toolkit
  8. Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
  9. ***********************************************************************************/
  10. namespace Standard
  11. {
  12. using System;
  13. using System.Diagnostics.CodeAnalysis;
  14. /// <summary>
  15. /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles.
  16. /// Note that FP noise is a big problem and using any of these compare
  17. /// methods is not a complete solution, but rather the way to reduce
  18. /// the probability of repeating unnecessary work.
  19. /// </summary>
  20. internal static class DoubleUtilities
  21. {
  22. /// <summary>
  23. /// Epsilon - more or less random, more or less small number.
  24. /// </summary>
  25. private const double Epsilon = 0.00000153;
  26. /// <summary>
  27. /// AreClose returns whether or not two doubles are "close". That is, whether or
  28. /// not they are within epsilon of each other.
  29. /// There are plenty of ways for this to return false even for numbers which
  30. /// are theoretically identical, so no code calling this should fail to work if this
  31. /// returns false.
  32. /// </summary>
  33. /// <param name="value1">The first double to compare.</param>
  34. /// <param name="value2">The second double to compare.</param>
  35. /// <returns>The result of the AreClose comparision.</returns>
  36. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  37. public static bool AreClose(double value1, double value2)
  38. {
  39. if (value1 == value2)
  40. {
  41. return true;
  42. }
  43. double delta = value1 - value2;
  44. return (delta < Epsilon) && (delta > -Epsilon);
  45. }
  46. /// <summary>
  47. /// LessThan returns whether or not the first double is less than the second double.
  48. /// That is, whether or not the first is strictly less than *and* not within epsilon of
  49. /// the other number.
  50. /// There are plenty of ways for this to return false even for numbers which
  51. /// are theoretically identical, so no code calling this should fail to work if this
  52. /// returns false.
  53. /// </summary>
  54. /// <param name="value1">The first double to compare.</param>
  55. /// <param name="value2">The second double to compare.</param>
  56. /// <returns>The result of the LessThan comparision.</returns>
  57. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  58. public static bool LessThan(double value1, double value2)
  59. {
  60. return (value1 < value2) && !AreClose(value1, value2);
  61. }
  62. /// <summary>
  63. /// GreaterThan returns whether or not the first double is greater than the second double.
  64. /// That is, whether or not the first is strictly greater than *and* not within epsilon of
  65. /// the other number.
  66. /// There are plenty of ways for this to return false even for numbers which
  67. /// are theoretically identical, so no code calling this should fail to work if this
  68. /// returns false.
  69. /// </summary>
  70. /// <param name="value1">The first double to compare.</param>
  71. /// <param name="value2">The second double to compare.</param>
  72. /// <returns>The result of the GreaterThan comparision.</returns>
  73. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  74. public static bool GreaterThan(double value1, double value2)
  75. {
  76. return (value1 > value2) && !AreClose(value1, value2);
  77. }
  78. /// <summary>
  79. /// LessThanOrClose returns whether or not the first double is less than or close to
  80. /// the second double. That is, whether or not the first is strictly less than or within
  81. /// epsilon of the other number.
  82. /// There are plenty of ways for this to return false even for numbers which
  83. /// are theoretically identical, so no code calling this should fail to work if this
  84. /// returns false.
  85. /// </summary>
  86. /// <param name="value1">The first double to compare.</param>
  87. /// <param name="value2">The second double to compare.</param>
  88. /// <returns>The result of the LessThanOrClose comparision.</returns>
  89. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  90. public static bool LessThanOrClose(double value1, double value2)
  91. {
  92. return (value1 < value2) || AreClose(value1, value2);
  93. }
  94. /// <summary>
  95. /// GreaterThanOrClose returns whether or not the first double is greater than or close to
  96. /// the second double. That is, whether or not the first is strictly greater than or within
  97. /// epsilon of the other number.
  98. /// There are plenty of ways for this to return false even for numbers which
  99. /// are theoretically identical, so no code calling this should fail to work if this
  100. /// returns false.
  101. /// </summary>
  102. /// <param name="value1">The first double to compare.</param>
  103. /// <param name="value2">The second double to compare.</param>
  104. /// <returns>The result of the GreaterThanOrClose comparision.</returns>
  105. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  106. public static bool GreaterThanOrClose(double value1, double value2)
  107. {
  108. return (value1 > value2) || AreClose(value1, value2);
  109. }
  110. /// <summary>
  111. /// Test to see if a double is a finite number (is not NaN or Infinity).
  112. /// </summary>
  113. /// <param name='value'>The value to test.</param>
  114. /// <returns>Whether or not the value is a finite number.</returns>
  115. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  116. public static bool IsFinite(double value)
  117. {
  118. return !double.IsNaN(value) && !double.IsInfinity(value);
  119. }
  120. /// <summary>
  121. /// Test to see if a double a valid size value (is finite and > 0).
  122. /// </summary>
  123. /// <param name='value'>The value to test.</param>
  124. /// <returns>Whether or not the value is a valid size value.</returns>
  125. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  126. public static bool IsValidSize(double value)
  127. {
  128. return IsFinite(value) && GreaterThanOrClose(value, 0);
  129. }
  130. }
  131. }