-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathDoubleUtil.cs
150 lines (137 loc) · 6.96 KB
/
DoubleUtil.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
namespace Standard
{
using System;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// 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.
/// </summary>
internal static class DoubleUtilities
{
/// <summary>
/// Epsilon - more or less random, more or less small number.
/// </summary>
private const double Epsilon = 0.00000153;
/// <summary>
/// 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.
/// </summary>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
/// <returns>The result of the AreClose comparision.</returns>
[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);
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsCloseTo(this double value1, double value2)
{
return AreClose(value1, value2);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
/// <returns>The result of the LessThan comparision.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsStrictlyLessThan(this double value1, double value2)
{
return (value1 < value2) && !AreClose(value1, value2);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
/// <returns>The result of the GreaterThan comparision.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsStrictlyGreaterThan(this double value1, double value2)
{
return (value1 > value2) && !AreClose(value1, value2);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
/// <returns>The result of the LessThanOrClose comparision.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsLessThanOrCloseTo(this double value1, double value2)
{
return (value1 < value2) || AreClose(value1, value2);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
/// <returns>The result of the GreaterThanOrClose comparision.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsGreaterThanOrCloseTo(this double value1, double value2)
{
return (value1 > value2) || AreClose(value1, value2);
}
/// <summary>
/// Test to see if a double is a finite number (is not NaN or Infinity).
/// </summary>
/// <param name='value'>The value to test.</param>
/// <returns>Whether or not the value is a finite number.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsFinite(this double value)
{
return !double.IsNaN(value) && !double.IsInfinity(value);
}
/// <summary>
/// Test to see if a double a valid size value (is finite and > 0).
/// </summary>
/// <param name='value'>The value to test.</param>
/// <returns>Whether or not the value is a valid size value.</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsValidSize(this double value)
{
return IsFinite(value) && value.IsGreaterThanOrCloseTo(0);
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static bool IsFiniteAndNonNegative(this double d)
{
if (double.IsNaN(d) || double.IsInfinity(d) || d < 0)
{
return false;
}
return true;
}
}
}