Pioneer
Loading...
Searching...
No Matches
FloatComparison.h
Go to the documentation of this file.
1// Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4#ifndef _FLOATCOMPARISON_H
5#define _FLOATCOMPARISON_H
6
7#include <SDL_stdinc.h>
8#include <limits>
9#ifdef _MSC_VER
10#include <float.h> // for _finite
11#else
12#include <cmath> // for std::isfinite
13#endif
14
15// Fuzzy floating point comparisons based on:
16// http://realtimecollisiondetection.net/blog/?p=89
17// (absolute & relative error tolerance)
18//
19// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
20// (ULP based tolerance)
21//
22// ULP-based tolerance implementation takes some architectural ideas from the
23// implementation in the Google test framework, and
24// http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison
25
26// provides (for float & double):
27
28// bool is_equal_exact(float a, float b);
29// bool is_equal_ulps(float a, float b, int ulps = DefaultUlpTolerance);
30// int32_t float_ulp_difference(float a, float b);
31// bool is_equal_relative(float a, float b, float tolerance = DefaultRelTolerance());
32// bool is_equal_absolute(float a, float b, float tolerance = DefaultAbsTolerance());
33// bool is_equal_general(float a, float b, float tolerance = DefaultTolerance());
34// bool is_equal_general(float a, float b, float relative_tolerance, float absolute_tolerance);
35
36// bool is_zero_exact(float x);
37// bool is_zero_general(float x, float tolerance = IEEEFloatTraits<float>::DefaultRelTolerance());
38
39// bool is_nan(float x);
40// bool is_finite(float x);
41
42// ====================================================================
43
44// in the following code, IEEEFloatTraits<T>::bool_type is used to limit
45// the application of the functions by SFINAE
46
47template <typename T>
48struct IEEEFloatTraits;
49
50// --- float function helpers
51
52template <typename T>
54{
55 return (x < T(0)) ? (-x) : x;
56}
57
58template <typename T>
60{
61 return (y > x) ? y : x;
62}
63
64template <typename T>
65inline typename IEEEFloatTraits<T>::float_type float_max(T x, T y, T z)
66{
67 return float_max(x, float_max(y, z));
68}
69
70// --- float property helpers
71
72template <typename T>
74{
75 typedef typename IEEEFloatTraits<T>::uint_type uint_type;
76 const uint_type top = IEEEFloatTraits<T>::TopBit;
77 const uint_type ebits = IEEEFloatTraits<T>::ExponentBits;
78
79 // NaN has the exponent bits set, and at least one mantissa bit set
80 // (therefore, if you mask off the top bit, the result must be strictly greater than
81 // just the exponent bits set; if it's equal then it's just an infinity; if it's
82 // less, then it's a valid finite number)
83 return ((bits & ~top) > ebits);
84}
85
86template <typename T>
88{
89 typedef typename IEEEFloatTraits<T>::uint_type uint_type;
90 const uint_type ebits = IEEEFloatTraits<T>::ExponentBits;
91 return ((bits & ebits) != ebits);
92}
93
94// --- infinity
95
96template <typename T>
98{
99#ifdef _MSC_VER
100 return _finite(x);
101#else
102 return std::isfinite(x);
103#endif
104}
105
106// --- exact comparisons, and checking for NaN
107
108#ifdef __GNUC__
109#pragma GCC diagnostic push
110#pragma GCC diagnostic ignored "-Wfloat-equal"
111#endif
112inline bool is_equal_exact(float a, float b)
113{
114 return (a == b);
115}
116inline bool is_equal_exact(double a, double b) { return (a == b); }
117
118inline bool is_zero_exact(float x) { return (x == 0.0f); }
119inline bool is_zero_exact(double x) { return (x == 0.0); }
120
121inline bool is_nan(float x) { return (x != x); }
122inline bool is_nan(double x) { return (x != x); }
123#ifdef __GNUC__
124#pragma GCC diagnostic pop
125#endif
126
127// --- relative & absolute error comparisons
128
129template <typename T>
131{
132 return (float_abs(a - b) <= tol * float_max(float_abs(a), float_abs(b)));
133}
134
135template <typename T>
137{
138 return (float_abs(a - b) <= tol);
139}
140
141template <typename T>
142inline typename IEEEFloatTraits<T>::bool_type is_equal_general(T a, T b, T rel_tol, T abs_tol)
143{
144 return (float_abs(a - b) <= float_max(abs_tol, rel_tol * float_max(float_abs(a), float_abs(b))));
145}
146
147template <typename T>
149{
150 return (float_abs(a - b) <= tol * float_max(T(1), float_abs(a), float_abs(b)));
151}
152
153template <typename T>
155{
156 return (float_abs(x) <= tol);
157}
158
159// --- ulp-based comparisons
160
161template <typename T>
163{
164 typedef typename IEEEFloatTraits<T>::FloatOrInt union_type;
165 union_type afi, bfi;
166 afi.f = a;
167 bfi.f = b;
168
169 // transform from sign-magnitude to two's-complement
170 if (afi.i < 0) afi.ui = (IEEEFloatTraits<T>::TopBit - afi.ui);
171 if (bfi.i < 0) bfi.ui = (IEEEFloatTraits<T>::TopBit - bfi.ui);
172
173 return (bfi.i - afi.i);
174}
175
176// IEEEFloatTraits<T>::bool_type used for SFINAE
177template <typename T>
179{
180 typedef typename IEEEFloatTraits<T>::FloatOrInt union_type;
181 typedef typename IEEEFloatTraits<T>::int_type int_type;
182 union_type afi, bfi;
183 afi.f = a;
184 bfi.f = b;
185
186 // Infinities aren't close to anything except themselves
187 if ((!is_finite_bits<T>(afi.ui) && is_finite_bits<T>(bfi.ui)) || (is_finite_bits<T>(afi.ui) && !is_finite_bits<T>(bfi.ui)))
188 return false;
189
190 // IEEE says NaNs are unequal to everything (even themselves)
191 if (is_nan_bits<T>(afi.ui) || is_nan_bits<T>(bfi.ui))
192 return false;
193
194 // transform from sign-magnitude to two's-complement
195 if (afi.i < 0) afi.ui = (IEEEFloatTraits<T>::TopBit - afi.ui);
196 if (bfi.i < 0) bfi.ui = (IEEEFloatTraits<T>::TopBit - bfi.ui);
197
198 int_type difference = (bfi.i - afi.i);
199 difference = (difference < int_type(0)) ? -difference : difference;
200 return (difference <= max_ulps);
201}
202
203// ====================================================================
204
205template <typename T>
207
208template <>
209struct IEEEFloatTraits<double> {
210 typedef double float_type;
211 typedef bool bool_type;
212
213 typedef int64_t int_type;
214 typedef uint64_t uint_type;
215
216 union FloatOrInt {
217 double f;
220 };
221
222 static const uint_type TopBit = static_cast<uint_type>(1) << (sizeof(double) * 8 - 1);
223 static const uint_type ExponentBits = (~static_cast<uint_type>(0) << std::numeric_limits<double>::digits) & ~TopBit;
224 static const uint_type MantissaBits = ~TopBit & ~ExponentBits;
225
226 static const int_type DefaultUlpTolerance = 16;
227
228 static double DefaultAbsTolerance() { return 1e-12; }
229 static double DefaultRelTolerance() { return 1e-6; }
230 static double DefaultTolerance() { return 1e-8; }
231 static double SmallestNormalisedValue() { return std::numeric_limits<double>::min(); }
232};
233
234template <>
235struct IEEEFloatTraits<float> {
236 typedef float float_type;
237 typedef bool bool_type;
238
239 typedef int32_t int_type;
240 typedef uint32_t uint_type;
241
242 union FloatOrInt {
243 float f;
246 };
247
248 static const uint_type TopBit = uint_type(1) << (sizeof(float) * 8 - 1);
249 static const uint_type ExponentBits = (~uint_type(0) << std::numeric_limits<float>::digits) & ~TopBit;
250 static const uint_type MantissaBits = ~TopBit & ~ExponentBits;
251
252 static const int_type DefaultUlpTolerance = 4;
253
254 static float DefaultAbsTolerance() { return 1e-6f; }
255 static float DefaultRelTolerance() { return 1e-5f; }
256 static float DefaultTolerance() { return 1e-5f; }
257 static float SmallestNormalisedValue() { return std::numeric_limits<float>::min(); }
258};
259
260#endif
IEEEFloatTraits< T >::bool_type is_equal_absolute(T a, T b, T tol=IEEEFloatTraits< T >::DefaultAbsTolerance())
Definition FloatComparison.h:136
IEEEFloatTraits< T >::bool_type is_nan_bits(const typename IEEEFloatTraits< T >::uint_type &bits)
Definition FloatComparison.h:73
IEEEFloatTraits< T >::bool_type is_equal_relative(T a, T b, T tol=IEEEFloatTraits< T >::DefaultRelTolerance())
Definition FloatComparison.h:130
bool is_zero_exact(float x)
Definition FloatComparison.h:118
IEEEFloatTraits< T >::float_type float_max(T x, T y)
Definition FloatComparison.h:59
IEEEFloatTraits< T >::bool_type is_zero_general(T x, T tol=IEEEFloatTraits< T >::DefaultRelTolerance())
Definition FloatComparison.h:154
IEEEFloatTraits< T >::float_type float_abs(T x)
Definition FloatComparison.h:53
IEEEFloatTraits< T >::int_type float_ulp_difference(T a, T b)
Definition FloatComparison.h:162
IEEEFloatTraits< T >::bool_type is_finite(T x)
Definition FloatComparison.h:97
IEEEFloatTraits< T >::bool_type is_equal_general(T a, T b, T rel_tol, T abs_tol)
Definition FloatComparison.h:142
bool is_equal_exact(float a, float b)
Definition FloatComparison.h:112
IEEEFloatTraits< T >::bool_type is_finite_bits(const typename IEEEFloatTraits< T >::uint_type &bits)
Definition FloatComparison.h:87
bool is_nan(float x)
Definition FloatComparison.h:121
IEEEFloatTraits< T >::bool_type is_equal_ulps(T a, T b, typename IEEEFloatTraits< T >::int_type max_ulps=IEEEFloatTraits< T >::DefaultUlpTolerance)
Definition FloatComparison.h:178
bool bool_type
Definition FloatComparison.h:211
uint64_t uint_type
Definition FloatComparison.h:214
static double DefaultRelTolerance()
Definition FloatComparison.h:229
int64_t int_type
Definition FloatComparison.h:213
double float_type
Definition FloatComparison.h:210
static double DefaultTolerance()
Definition FloatComparison.h:230
static double SmallestNormalisedValue()
Definition FloatComparison.h:231
static double DefaultAbsTolerance()
Definition FloatComparison.h:228
static float DefaultAbsTolerance()
Definition FloatComparison.h:254
static float DefaultTolerance()
Definition FloatComparison.h:256
int32_t int_type
Definition FloatComparison.h:239
float float_type
Definition FloatComparison.h:236
bool bool_type
Definition FloatComparison.h:237
static float DefaultRelTolerance()
Definition FloatComparison.h:255
uint32_t uint_type
Definition FloatComparison.h:240
static float SmallestNormalisedValue()
Definition FloatComparison.h:257
Definition FloatComparison.h:206
int_type i
Definition FloatComparison.h:219
uint_type ui
Definition FloatComparison.h:218
double f
Definition FloatComparison.h:217
int_type i
Definition FloatComparison.h:245
uint_type ui
Definition FloatComparison.h:244
float f
Definition FloatComparison.h:243