PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/NUnit/framework/Constraints/FloatingPointNumerics.cs

#
C# | 238 lines | 89 code | 32 blank | 117 comment | 0 complexity | 24b39dcae0773683ab3ad510e1da42a6 MD5 | raw file
Possible License(s): GPL-2.0
  1. // ****************************************************************
  2. // Copyright 2008, Charlie Poole
  3. // This is free software licensed under the NUnit license. You may
  4. // obtain a copy of the license at http://nunit.org
  5. // ****************************************************************
  6. #if !NETCF_1_0
  7. using System;
  8. using System.Runtime.InteropServices;
  9. namespace NUnit.Framework.Constraints
  10. {
  11. /// <summary>Helper routines for working with floating point numbers</summary>
  12. /// <remarks>
  13. /// <para>
  14. /// The floating point comparison code is based on this excellent article:
  15. /// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
  16. /// </para>
  17. /// <para>
  18. /// "ULP" means Unit in the Last Place and in the context of this library refers to
  19. /// the distance between two adjacent floating point numbers. IEEE floating point
  20. /// numbers can only represent a finite subset of natural numbers, with greater
  21. /// accuracy for smaller numbers and lower accuracy for very large numbers.
  22. /// </para>
  23. /// <para>
  24. /// If a comparison is allowed "2 ulps" of deviation, that means the values are
  25. /// allowed to deviate by up to 2 adjacent floating point values, which might be
  26. /// as low as 0.0000001 for small numbers or as high as 10.0 for large numbers.
  27. /// </para>
  28. /// </remarks>
  29. public class FloatingPointNumerics
  30. {
  31. #region struct FloatIntUnion
  32. /// <summary>Union of a floating point variable and an integer</summary>
  33. [StructLayout(LayoutKind.Explicit)]
  34. private struct FloatIntUnion
  35. {
  36. /// <summary>The union's value as a floating point variable</summary>
  37. [FieldOffset(0)]
  38. public float Float;
  39. /// <summary>The union's value as an integer</summary>
  40. [FieldOffset(0)]
  41. public int Int;
  42. /// <summary>The union's value as an unsigned integer</summary>
  43. [FieldOffset(0)]
  44. public uint UInt;
  45. }
  46. #endregion // struct FloatIntUnion
  47. #region struct DoubleLongUnion
  48. /// <summary>Union of a double precision floating point variable and a long</summary>
  49. [StructLayout(LayoutKind.Explicit)]
  50. private struct DoubleLongUnion
  51. {
  52. /// <summary>The union's value as a double precision floating point variable</summary>
  53. [FieldOffset(0)]
  54. public double Double;
  55. /// <summary>The union's value as a long</summary>
  56. [FieldOffset(0)]
  57. public long Long;
  58. /// <summary>The union's value as an unsigned long</summary>
  59. [FieldOffset(0)]
  60. public ulong ULong;
  61. }
  62. #endregion // struct DoubleLongUnion
  63. /// <summary>Compares two floating point values for equality</summary>
  64. /// <param name="left">First floating point value to be compared</param>
  65. /// <param name="right">Second floating point value t be compared</param>
  66. /// <param name="maxUlps">
  67. /// Maximum number of representable floating point values that are allowed to
  68. /// be between the left and the right floating point values
  69. /// </param>
  70. /// <returns>True if both numbers are equal or close to being equal</returns>
  71. /// <remarks>
  72. /// <para>
  73. /// Floating point values can only represent a finite subset of natural numbers.
  74. /// For example, the values 2.00000000 and 2.00000024 can be stored in a float,
  75. /// but nothing inbetween them.
  76. /// </para>
  77. /// <para>
  78. /// This comparison will count how many possible floating point values are between
  79. /// the left and the right number. If the number of possible values between both
  80. /// numbers is less than or equal to maxUlps, then the numbers are considered as
  81. /// being equal.
  82. /// </para>
  83. /// <para>
  84. /// Implementation partially follows the code outlined here:
  85. /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
  86. /// </para>
  87. /// </remarks>
  88. public static bool AreAlmostEqualUlps(float left, float right, int maxUlps)
  89. {
  90. FloatIntUnion leftUnion = new FloatIntUnion();
  91. FloatIntUnion rightUnion = new FloatIntUnion();
  92. leftUnion.Float = left;
  93. rightUnion.Float = right;
  94. uint leftSignMask = (leftUnion.UInt >> 31);
  95. uint rightSignMask = (rightUnion.UInt >> 31);
  96. uint leftTemp = ((0x80000000 - leftUnion.UInt) & leftSignMask);
  97. leftUnion.UInt = leftTemp | (leftUnion.UInt & ~leftSignMask);
  98. uint rightTemp = ((0x80000000 - rightUnion.UInt) & rightSignMask);
  99. rightUnion.UInt = rightTemp | (rightUnion.UInt & ~rightSignMask);
  100. return (Math.Abs(leftUnion.Int - rightUnion.Int) <= maxUlps);
  101. }
  102. /// <summary>Compares two double precision floating point values for equality</summary>
  103. /// <param name="left">First double precision floating point value to be compared</param>
  104. /// <param name="right">Second double precision floating point value t be compared</param>
  105. /// <param name="maxUlps">
  106. /// Maximum number of representable double precision floating point values that are
  107. /// allowed to be between the left and the right double precision floating point values
  108. /// </param>
  109. /// <returns>True if both numbers are equal or close to being equal</returns>
  110. /// <remarks>
  111. /// <para>
  112. /// Double precision floating point values can only represent a limited series of
  113. /// natural numbers. For example, the values 2.0000000000000000 and 2.0000000000000004
  114. /// can be stored in a double, but nothing inbetween them.
  115. /// </para>
  116. /// <para>
  117. /// This comparison will count how many possible double precision floating point
  118. /// values are between the left and the right number. If the number of possible
  119. /// values between both numbers is less than or equal to maxUlps, then the numbers
  120. /// are considered as being equal.
  121. /// </para>
  122. /// <para>
  123. /// Implementation partially follows the code outlined here:
  124. /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
  125. /// </para>
  126. /// </remarks>
  127. public static bool AreAlmostEqualUlps(double left, double right, long maxUlps)
  128. {
  129. DoubleLongUnion leftUnion = new DoubleLongUnion();
  130. DoubleLongUnion rightUnion = new DoubleLongUnion();
  131. leftUnion.Double = left;
  132. rightUnion.Double = right;
  133. ulong leftSignMask = (leftUnion.ULong >> 63);
  134. ulong rightSignMask = (rightUnion.ULong >> 63);
  135. ulong leftTemp = ((0x8000000000000000 - leftUnion.ULong) & leftSignMask);
  136. leftUnion.ULong = leftTemp | (leftUnion.ULong & ~leftSignMask);
  137. ulong rightTemp = ((0x8000000000000000 - rightUnion.ULong) & rightSignMask);
  138. rightUnion.ULong = rightTemp | (rightUnion.ULong & ~rightSignMask);
  139. return (Math.Abs(leftUnion.Long - rightUnion.Long) <= maxUlps);
  140. }
  141. /// <summary>
  142. /// Reinterprets the memory contents of a floating point value as an integer value
  143. /// </summary>
  144. /// <param name="value">
  145. /// Floating point value whose memory contents to reinterpret
  146. /// </param>
  147. /// <returns>
  148. /// The memory contents of the floating point value interpreted as an integer
  149. /// </returns>
  150. public static int ReinterpretAsInt(float value)
  151. {
  152. FloatIntUnion union = new FloatIntUnion();
  153. union.Float = value;
  154. return union.Int;
  155. }
  156. /// <summary>
  157. /// Reinterprets the memory contents of a double precision floating point
  158. /// value as an integer value
  159. /// </summary>
  160. /// <param name="value">
  161. /// Double precision floating point value whose memory contents to reinterpret
  162. /// </param>
  163. /// <returns>
  164. /// The memory contents of the double precision floating point value
  165. /// interpreted as an integer
  166. /// </returns>
  167. public static long ReinterpretAsLong(double value)
  168. {
  169. DoubleLongUnion union = new DoubleLongUnion();
  170. union.Double = value;
  171. return union.Long;
  172. }
  173. /// <summary>
  174. /// Reinterprets the memory contents of an integer as a floating point value
  175. /// </summary>
  176. /// <param name="value">Integer value whose memory contents to reinterpret</param>
  177. /// <returns>
  178. /// The memory contents of the integer value interpreted as a floating point value
  179. /// </returns>
  180. public static float ReinterpretAsFloat(int value)
  181. {
  182. FloatIntUnion union = new FloatIntUnion();
  183. union.Int = value;
  184. return union.Float;
  185. }
  186. /// <summary>
  187. /// Reinterprets the memory contents of an integer value as a double precision
  188. /// floating point value
  189. /// </summary>
  190. /// <param name="value">Integer whose memory contents to reinterpret</param>
  191. /// <returns>
  192. /// The memory contents of the integer interpreted as a double precision
  193. /// floating point value
  194. /// </returns>
  195. public static double ReinterpretAsDouble(long value)
  196. {
  197. DoubleLongUnion union = new DoubleLongUnion();
  198. union.Long = value;
  199. return union.Double;
  200. }
  201. private FloatingPointNumerics()
  202. {
  203. }
  204. }
  205. }
  206. #endif