1 // ***********************************************************************
2 // Copyright (c) 2009 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
30 using System.Runtime.InteropServices;
32 namespace NUnit.Framework.Constraints
35 /// <summary>Helper routines for working with floating point numbers</summary>
38 /// The floating point comparison code is based on this excellent article:
39 /// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
42 /// "ULP" means Unit in the Last Place and in the context of this library refers to
43 /// the distance between two adjacent floating point numbers. IEEE floating point
44 /// numbers can only represent a finite subset of natural numbers, with greater
45 /// accuracy for smaller numbers and lower accuracy for very large numbers.
48 /// If a comparison is allowed "2 ulps" of deviation, that means the _values are
49 /// allowed to deviate by up to 2 adjacent floating point _values, which might be
50 /// as low as 0.0000001 for small numbers or as high as 10.0 for large numbers.
53 public class FloatingPointNumerics
56 #region struct FloatIntUnion
58 /// <summary>Union of a floating point variable and an integer</summary>
59 [StructLayout(LayoutKind.Explicit)]
60 private struct FloatIntUnion
62 /// <summary>The union's value as a floating point variable</summary>
66 /// <summary>The union's value as an integer</summary>
70 /// <summary>The union's value as an unsigned integer</summary>
75 #endregion // struct FloatIntUnion
77 #region struct DoubleLongUnion
79 /// <summary>Union of a double precision floating point variable and a long</summary>
80 [StructLayout(LayoutKind.Explicit)]
81 private struct DoubleLongUnion
83 /// <summary>The union's value as a double precision floating point variable</summary>
87 /// <summary>The union's value as a long</summary>
91 /// <summary>The union's value as an unsigned long</summary>
96 #endregion // struct DoubleLongUnion
98 /// <summary>Compares two floating point _values for equality</summary>
99 /// <param name="left">First floating point value to be compared</param>
100 /// <param name="right">Second floating point value t be compared</param>
101 /// <param name="maxUlps">
102 /// Maximum number of representable floating point _values that are allowed to
103 /// be between the left and the right floating point _values
105 /// <returns>True if both numbers are equal or close to being equal</returns>
108 /// Floating point _values can only represent a finite subset of natural numbers.
109 /// For example, the _values 2.00000000 and 2.00000024 can be stored in a float,
110 /// but nothing inbetween them.
113 /// This comparison will count how many possible floating point _values are between
114 /// the left and the right number. If the number of possible _values between both
115 /// numbers is less than or equal to maxUlps, then the numbers are considered as
119 /// Implementation partially follows the code outlined here:
120 /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
123 public static bool AreAlmostEqualUlps(float left, float right, int maxUlps)
125 FloatIntUnion leftUnion = new FloatIntUnion();
126 FloatIntUnion rightUnion = new FloatIntUnion();
128 leftUnion.Float = left;
129 rightUnion.Float = right;
131 uint leftSignMask = (leftUnion.UInt >> 31);
132 uint rightSignMask = (rightUnion.UInt >> 31);
134 uint leftTemp = ((0x80000000 - leftUnion.UInt) & leftSignMask);
135 leftUnion.UInt = leftTemp | (leftUnion.UInt & ~leftSignMask);
137 uint rightTemp = ((0x80000000 - rightUnion.UInt) & rightSignMask);
138 rightUnion.UInt = rightTemp | (rightUnion.UInt & ~rightSignMask);
140 if (leftSignMask != rightSignMask) // Overflow possible, check each against zero
142 if (Math.Abs(leftUnion.Int) > maxUlps || Math.Abs(rightUnion.Int) > maxUlps)
146 // Either they have the same sign or both are very close to zero
147 return Math.Abs(leftUnion.Int - rightUnion.Int) <= maxUlps;
150 /// <summary>Compares two double precision floating point _values for equality</summary>
151 /// <param name="left">First double precision floating point value to be compared</param>
152 /// <param name="right">Second double precision floating point value t be compared</param>
153 /// <param name="maxUlps">
154 /// Maximum number of representable double precision floating point _values that are
155 /// allowed to be between the left and the right double precision floating point _values
157 /// <returns>True if both numbers are equal or close to being equal</returns>
160 /// Double precision floating point _values can only represent a limited series of
161 /// natural numbers. For example, the _values 2.0000000000000000 and 2.0000000000000004
162 /// can be stored in a double, but nothing inbetween them.
165 /// This comparison will count how many possible double precision floating point
166 /// _values are between the left and the right number. If the number of possible
167 /// _values between both numbers is less than or equal to maxUlps, then the numbers
168 /// are considered as being equal.
171 /// Implementation partially follows the code outlined here:
172 /// http://www.anttirt.net/2007/08/19/proper-floating-point-comparisons/
175 public static bool AreAlmostEqualUlps(double left, double right, long maxUlps)
177 DoubleLongUnion leftUnion = new DoubleLongUnion();
178 DoubleLongUnion rightUnion = new DoubleLongUnion();
180 leftUnion.Double = left;
181 rightUnion.Double = right;
183 ulong leftSignMask = (leftUnion.ULong >> 63);
184 ulong rightSignMask = (rightUnion.ULong >> 63);
186 ulong leftTemp = ((0x8000000000000000 - leftUnion.ULong) & leftSignMask);
187 leftUnion.ULong = leftTemp | (leftUnion.ULong & ~leftSignMask);
189 ulong rightTemp = ((0x8000000000000000 - rightUnion.ULong) & rightSignMask);
190 rightUnion.ULong = rightTemp | (rightUnion.ULong & ~rightSignMask);
192 if (leftSignMask != rightSignMask) // Overflow possible, check each against zero
194 if (Math.Abs(leftUnion.Long) > maxUlps || Math.Abs(rightUnion.Long) > maxUlps)
198 // Either they have the same sign or both are very close to zero
199 return Math.Abs(leftUnion.Long - rightUnion.Long) <= maxUlps;
203 /// Reinterprets the memory contents of a floating point value as an integer value
205 /// <param name="value">
206 /// Floating point value whose memory contents to reinterpret
209 /// The memory contents of the floating point value interpreted as an integer
211 public static int ReinterpretAsInt(float value)
213 FloatIntUnion union = new FloatIntUnion();
219 /// Reinterprets the memory contents of a double precision floating point
220 /// value as an integer value
222 /// <param name="value">
223 /// Double precision floating point value whose memory contents to reinterpret
226 /// The memory contents of the double precision floating point value
227 /// interpreted as an integer
229 public static long ReinterpretAsLong(double value)
231 DoubleLongUnion union = new DoubleLongUnion();
232 union.Double = value;
237 /// Reinterprets the memory contents of an integer as a floating point value
239 /// <param name="value">Integer value whose memory contents to reinterpret</param>
241 /// The memory contents of the integer value interpreted as a floating point value
243 public static float ReinterpretAsFloat(int value)
245 FloatIntUnion union = new FloatIntUnion();
251 /// Reinterprets the memory contents of an integer value as a double precision
252 /// floating point value
254 /// <param name="value">Integer whose memory contents to reinterpret</param>
256 /// The memory contents of the integer interpreted as a double precision
257 /// floating point value
259 public static double ReinterpretAsDouble(long value)
261 DoubleLongUnion union = new DoubleLongUnion();
266 private FloatingPointNumerics()