16
16
17
17
namespace Mantid ::Kernel {
18
18
19
+ /* *
20
+ * Compare numbers for equality to within machine epsilon.
21
+ * @param x :: LHS comparator
22
+ * @param y :: RHS comparator
23
+ * @returns True if the numbers are considered equal within machine precision.
24
+ * Machine precision is a 1 at the least significant bit scaled to the same power as the numbers compared.
25
+ * E.g. for 1, it is usually 1x2^{-52}
26
+ * E.g. for 1x2^100, it is usually 1x2^{-52} x 1x2^100 = 1x2^{48}
27
+ * False if any value is NaN. False if comparing opposite infinities.
28
+ */
29
+ template <typename T> bool equals (T const x, T const y) { return equals (x, y, std::is_integral<T>()); }
30
+
31
+ /* *
32
+ * Compare integer numbers
33
+ * @param x :: LHS comparator
34
+ * @param y :: RHS comparator
35
+ * @returns True if the numbers are considered equal
36
+ */
37
+ template <typename T> inline bool equals (T const x, T const y, std::true_type) { return x == y; }
38
+
19
39
/* *
20
40
* Compare floating point numbers for equality to within
21
41
* std::numeric_limits<TYPE>::epsilon precision
@@ -27,7 +47,7 @@ namespace Mantid::Kernel {
27
47
* E.g. for 1x2^100, it is usually 1x2^{-52} x 1x2^100 = 1x2^{48}
28
48
* False if any value is NaN. False if comparing opposite infinities.
29
49
*/
30
- template <typename T> bool equals (T const x, T const y) {
50
+ template <typename T> inline bool equals (T const x, T const y, std::false_type ) {
31
51
// handle infinities
32
52
if (std::isinf (x) && std::isinf (y)) {
33
53
// if x,y both +inf, x-y=NaN; if x,y both -inf, x-y=NaN; else not an NaN
@@ -104,6 +124,26 @@ template <typename T> T relativeDifference(T const x, T const y) {
104
124
* false otherwise. False if either value is NaN.
105
125
*/
106
126
template <typename T, typename S> bool withinAbsoluteDifference (T const x, T const y, S const tolerance) {
127
+ return withinAbsoluteDifference (x, y, tolerance, std::is_integral<T>());
128
+ }
129
+
130
+ // specialization for integer types
131
+ template <typename T, typename S>
132
+ inline bool withinAbsoluteDifference (T const x, T const y, S const tolerance, std::true_type) {
133
+ return ltEquals (static_cast <S>(std::llabs (x - y)), tolerance);
134
+ }
135
+
136
+ /* *
137
+ * Compare floating point numbers for absolute difference to
138
+ * within the given tolerance
139
+ * @param x :: first value
140
+ * @param y :: second value
141
+ * @param tolerance :: the tolerance
142
+ * @returns True if the numbers are considered equal within the given tolerance,
143
+ * false otherwise. False if either value is NaN.
144
+ */
145
+ template <typename T, typename S>
146
+ inline bool withinAbsoluteDifference (T const x, T const y, S const tolerance, std::false_type) {
107
147
// handle the case of infinities
108
148
if (std::isinf (x) && std::isinf (y))
109
149
// if both are +inf, return true; if both -inf, return true; else false
@@ -121,6 +161,31 @@ template <typename T, typename S> bool withinAbsoluteDifference(T const x, T con
121
161
* false otherwise. False if either value is NaN.
122
162
*/
123
163
template <typename T, typename S> bool withinRelativeDifference (T const x, T const y, S const tolerance) {
164
+ return withinRelativeDifference (x, y, tolerance, std::is_integral<T>());
165
+ }
166
+
167
+ template <typename T, typename S>
168
+ inline bool withinRelativeDifference (T const x, T const y, S const tolerance, std::true_type) {
169
+ S const num = static_cast <S>(std::llabs (x - y));
170
+ if (num == static_cast <S>(0 )) {
171
+ return true ;
172
+ } else {
173
+ S const denom = static_cast <S>(std::llabs (x) + std::llabs (y));
174
+ return num <= static_cast <S>(2 ) * denom * tolerance;
175
+ }
176
+ }
177
+
178
+ /* *
179
+ * Compare floating point numbers for relative difference to
180
+ * within the given tolerance
181
+ * @param x :: first value
182
+ * @param y :: second value
183
+ * @param tolerance :: the tolerance
184
+ * @returns True if the numbers are considered equal within the given tolerance,
185
+ * false otherwise. False if either value is NaN.
186
+ */
187
+ template <typename T, typename S>
188
+ inline bool withinRelativeDifference (T const x, T const y, S const tolerance, std::false_type) {
124
189
// handles the case of infinities
125
190
if (std::isinf (x) && std::isinf (y))
126
191
// if both are +inf, return true; if both -inf, return true; else false
@@ -131,7 +196,7 @@ template <typename T, typename S> bool withinRelativeDifference(T const x, T con
131
196
return true ;
132
197
} else {
133
198
// otherwise we have to calculate the denominator
134
- S const denom = static_cast <S>(std::abs (x) + std::abs (y)) / static_cast <S>( 2 );
199
+ S const denom = static_cast <S>(0.5 ) * static_cast <S>( std::abs (x) + std::abs (y));
135
200
// if denom <= 1, then |x-y| > tol implies |x-y|/denom > tol, can return early
136
201
// NOTE can only return early if BOTH denom > tol AND |x-y| > tol.
137
202
if (denom <= static_cast <S>(1 ) && !ltEquals (num, tolerance)) {
@@ -156,73 +221,40 @@ template DLLExport double absoluteDifference<double>(double const, double const)
156
221
template DLLExport float absoluteDifference<float >(float const , float const );
157
222
template DLLExport double relativeDifference<double >(double const , double const );
158
223
template DLLExport float relativeDifference<float >(float const , float const );
159
- // within difference methods
224
+ // within difference methods -- object and tolerance same
160
225
template DLLExport bool withinAbsoluteDifference<double >(double const , double const , double const );
161
226
template DLLExport bool withinAbsoluteDifference<float >(float const , float const , float const );
227
+ template DLLExport bool withinAbsoluteDifference<int >(int const , int const , int const );
228
+ template DLLExport bool withinAbsoluteDifference<unsigned int >(unsigned int const , unsigned int const ,
229
+ unsigned int const );
230
+ template DLLExport bool withinAbsoluteDifference<long >(long const , long const , long const );
231
+ template DLLExport bool withinAbsoluteDifference<long long >(long long const , long long const , long long const );
232
+ //
162
233
template DLLExport bool withinRelativeDifference<double >(double const , double const , double const );
163
234
template DLLExport bool withinRelativeDifference<float >(float const , float const , float const );
164
- // instantiations where the objects are anything and tolerance is a double
235
+ template DLLExport bool withinRelativeDifference<int >(int const , int const , int const );
236
+ template DLLExport bool withinRelativeDifference<unsigned int >(unsigned int const , unsigned int const ,
237
+ unsigned int const );
238
+ template DLLExport bool withinRelativeDifference<long >(long const , long const , long const );
239
+ template DLLExport bool withinRelativeDifference<long long >(long long const , long long const , long long const );
240
+ // within difference methods -- tolerance is double
165
241
template DLLExport bool withinAbsoluteDifference<float , double >(float const , float const , double const );
166
242
template DLLExport bool withinAbsoluteDifference<int , double >(int const , int const , double const );
243
+ template DLLExport bool withinAbsoluteDifference<unsigned int , double >(unsigned int const , unsigned int const ,
244
+ double const );
167
245
template DLLExport bool withinAbsoluteDifference<long , double >(long const , long const , double const );
246
+ template DLLExport bool withinAbsoluteDifference<unsigned long , double >(unsigned long const , unsigned long const ,
247
+ double const );
248
+ template DLLExport bool withinAbsoluteDifference<long long , double >(long long const , long long const , double const );
249
+ //
168
250
template DLLExport bool withinRelativeDifference<float , double >(float const , float const , double const );
169
251
template DLLExport bool withinRelativeDifference<int , double >(int const , int const , double const );
252
+ template DLLExport bool withinRelativeDifference<unsigned int , double >(unsigned int const , unsigned int const ,
253
+ double const );
170
254
template DLLExport bool withinRelativeDifference<long , double >(long const , long const , double const );
255
+ template DLLExport bool withinRelativeDifference<unsigned long , double >(unsigned long const , unsigned long const ,
256
+ double const );
257
+ template DLLExport bool withinRelativeDifference<long long , double >(long long const , long long const , double const );
171
258
// /@endcond
172
259
173
- // / Template specialization for long int
174
- // / these prevent compiler warnings about using isinf and isnan on longs
175
-
176
- template <> DLLExport bool equals<long >(long const x, long const y) { return x == y; }
177
-
178
- template <> DLLExport bool withinAbsoluteDifference<long >(long const x, long const y, long const tolerance) {
179
- return ltEquals (std::labs (x - y), tolerance);
180
- }
181
-
182
- template <> DLLExport bool withinRelativeDifference<long >(long const x, long const y, long const tolerance) {
183
- long const num = std::labs (x - y);
184
- if (num == 0 ) {
185
- return true ;
186
- } else {
187
- long const denom = (std::labs (x) + std::labs (y)) / 2 ;
188
- return num <= static_cast <long >(denom * tolerance);
189
- }
190
- }
191
-
192
- // / Template specialization for long long int
193
- // / these prevent compiler warnings about using isinf and isnan on longs
194
-
195
- template <> DLLExport bool equals<long long >(long long const x, long long const y) { return x == y; }
196
-
197
- template <>
198
- DLLExport bool withinAbsoluteDifference<long long >(long long const x, long long const y, long long const tolerance) {
199
- return ltEquals (std::llabs (x - y), tolerance);
200
- }
201
-
202
- template <>
203
- DLLExport bool withinRelativeDifference<long long >(long long const x, long long const y, long long const tolerance) {
204
- long long const num = std::llabs (x - y);
205
- if (num == 0 ) {
206
- return true ;
207
- } else {
208
- long long const denom = (std::llabs (x) + std::llabs (y)) / 2 ;
209
- return num <= static_cast <long long >(denom * tolerance);
210
- }
211
- }
212
-
213
- // / Template specialization for unsigned int
214
-
215
- template <>
216
- DLLExport bool withinAbsoluteDifference<unsigned int , double >(unsigned int const x, unsigned int const y,
217
- double const tol) {
218
- unsigned int roundedTol = static_cast <unsigned int >(llround (tol));
219
- return std::llabs (x - y) <= roundedTol;
220
- }
221
- template <>
222
- DLLExport bool withinRelativeDifference<unsigned int , double >(unsigned int const x, unsigned int const y,
223
- double const tol) {
224
- unsigned int roundedTol = static_cast <unsigned int >(llround (tol));
225
- return std::llabs (x - y) <= roundedTol;
226
- }
227
-
228
260
} // namespace Mantid::Kernel
0 commit comments