dune-common 2.8.0
Loading...
Searching...
No Matches
float_cmp.cc
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#include "float_cmp.hh"
4
5#include <vector>
6#include <limits>
7#include <algorithm>
8#include <cstdlib>
10
11namespace Dune {
12
13
14 namespace FloatCmp {
15 // traits
17
21 template<class T> struct EpsilonType {
23 typedef T Type;
24 };
26
31 template<class T, typename A>
32 struct EpsilonType<std::vector<T, A> > {
34 typedef typename EpsilonType<T>::Type Type;
35 };
37
42 template<class T, int n>
43 struct EpsilonType<FieldVector<T, n> > {
45 typedef typename EpsilonType<T>::Type Type;
46 };
47
48 // default epsilon
49 template<class T>
51 static typename EpsilonType<T>::Type value()
53 };
54 template<class T>
56 static typename EpsilonType<T>::Type value()
58 };
59 template<class T>
61 static typename EpsilonType<T>::Type value()
62 { return std::max(std::numeric_limits<typename EpsilonType<T>::Type>::epsilon(), 1e-6); }
63 };
64
65 namespace Impl {
66 // basic comparison
67 template<class T, CmpStyle style = defaultCmpStyle>
68 struct eq_t;
69 template<class T>
70 struct eq_t<T, relativeWeak> {
71 static bool eq(const T &first,
72 const T &second,
74 {
75 using std::abs;
76 return abs(first - second) <= epsilon*std::max(abs(first), abs(second));
77 }
78 };
79 template<class T>
80 struct eq_t<T, relativeStrong> {
81 static bool eq(const T &first,
82 const T &second,
84 {
85 using std::abs;
86 return abs(first - second) <= epsilon*std::min(abs(first), abs(second));
87 }
88 };
89 template<class T>
90 struct eq_t<T, absolute> {
91 static bool eq(const T &first,
92 const T &second,
94 {
95 using std::abs;
96 return abs(first-second) <= epsilon;
97 }
98 };
99 template<class T, CmpStyle cstyle>
100 struct eq_t_std_vec {
101 typedef std::vector<T> V;
102 static bool eq(const V &first,
103 const V &second,
104 typename EpsilonType<V>::Type epsilon = DefaultEpsilon<V>::value()) {
105 auto size = first.size();
106 if(size != second.size()) return false;
107 for(unsigned int i = 0; i < size; ++i)
108 if(!eq_t<T, cstyle>::eq(first[i], second[i], epsilon))
109 return false;
110 return true;
111 }
112 };
113 template< class T>
114 struct eq_t<std::vector<T>, relativeWeak> : eq_t_std_vec<T, relativeWeak> {};
115 template< class T>
116 struct eq_t<std::vector<T>, relativeStrong> : eq_t_std_vec<T, relativeStrong> {};
117 template< class T>
118 struct eq_t<std::vector<T>, absolute> : eq_t_std_vec<T, absolute> {};
119
120 template<class T, int n, CmpStyle cstyle>
121 struct eq_t_fvec {
122 typedef Dune::FieldVector<T, n> V;
123 static bool eq(const V &first,
124 const V &second,
125 typename EpsilonType<V>::Type epsilon = DefaultEpsilon<V>::value()) {
126 for(int i = 0; i < n; ++i)
127 if(!eq_t<T, cstyle>::eq(first[i], second[i], epsilon))
128 return false;
129 return true;
130 }
131 };
132 template< class T, int n >
133 struct eq_t< Dune::FieldVector<T, n>, relativeWeak> : eq_t_fvec<T, n, relativeWeak> {};
134 template< class T, int n >
135 struct eq_t< Dune::FieldVector<T, n>, relativeStrong> : eq_t_fvec<T, n, relativeStrong> {};
136 template< class T, int n >
137 struct eq_t< Dune::FieldVector<T, n>, absolute> : eq_t_fvec<T, n, absolute> {};
138 } // namespace Impl
139
140 // operations in functional style
141 template <class T, CmpStyle style>
142 bool eq(const T &first,
143 const T &second,
144 typename EpsilonType<T>::Type epsilon)
145 {
146 return Impl::eq_t<T, style>::eq(first, second, epsilon);
147 }
148 template <class T, CmpStyle style>
149 bool ne(const T &first,
150 const T &second,
151 typename EpsilonType<T>::Type epsilon)
152 {
153 return !eq<T, style>(first, second, epsilon);
154 }
155 template <class T, CmpStyle style>
156 bool gt(const T &first,
157 const T &second,
158 typename EpsilonType<T>::Type epsilon)
159 {
160 return first > second && ne<T, style>(first, second, epsilon);
161 }
162 template <class T, CmpStyle style>
163 bool lt(const T &first,
164 const T &second,
165 typename EpsilonType<T>::Type epsilon)
166 {
167 return first < second && ne<T, style>(first, second, epsilon);
168 }
169 template <class T, CmpStyle style>
170 bool ge(const T &first,
171 const T &second,
172 typename EpsilonType<T>::Type epsilon)
173 {
174 return first > second || eq<T, style>(first, second, epsilon);
175 }
176 template <class T, CmpStyle style>
177 bool le(const T &first,
178 const T &second,
179 typename EpsilonType<T>::Type epsilon)
180 {
181 return first < second || eq<T, style>(first, second, epsilon);
182 }
183
184 // default template arguments
185 template <class T>
186 bool eq(const T &first,
187 const T &second,
189 {
190 return eq<T, defaultCmpStyle>(first, second, epsilon);
191 }
192 template <class T>
193 bool ne(const T &first,
194 const T &second,
196 {
197 return ne<T, defaultCmpStyle>(first, second, epsilon);
198 }
199 template <class T>
200 bool gt(const T &first,
201 const T &second,
203 {
204 return gt<T, defaultCmpStyle>(first, second, epsilon);
205 }
206 template <class T>
207 bool lt(const T &first,
208 const T &second,
210 {
211 return lt<T, defaultCmpStyle>(first, second, epsilon);
212 }
213 template <class T>
214 bool ge(const T &first,
215 const T &second,
217 {
218 return ge<T, defaultCmpStyle>(first, second, epsilon);
219 }
220 template <class T>
221 bool le(const T &first,
222 const T &second,
224 {
225 return le<T, defaultCmpStyle>(first, second, epsilon);
226 }
227
228 // rounding operations
229 namespace Impl {
230 template<class I, class T, CmpStyle cstyle = defaultCmpStyle, RoundingStyle rstyle = defaultRoundingStyle>
231 struct round_t;
232 template<class I, class T, CmpStyle cstyle>
233 struct round_t<I, T, cstyle, downward> {
234 static I
235 round(const T &val,
237 // first get an approximation
238 I lower = I(val);
239 I upper;
240 if(eq<T, cstyle>(T(lower), val, epsilon)) return lower;
241 if(T(lower) > val) { upper = lower; lower--; }
242 else upper = lower+1;
243 if(le<T, cstyle>(val - T(lower), T(upper) - val, epsilon))
244 return lower;
245 else return upper;
246 }
247 };
248 template<class I, class T, CmpStyle cstyle>
249 struct round_t<I, T, cstyle, upward> {
250 static I
251 round(const T &val,
253 // first get an approximation
254 I lower = I(val);
255 I upper;
256 if(eq<T, cstyle>(T(lower), val, epsilon)) return lower;
257 if(T(lower) > val) { upper = lower; lower--; }
258 else upper = lower+1;
259 if(lt<T, cstyle>(val - T(lower), T(upper) - val, epsilon))
260 return lower;
261 else return upper;
262 }
263 };
264 template<class I, class T, CmpStyle cstyle>
265 struct round_t<I, T, cstyle, towardZero> {
266 static I
267 round(const T &val,
269 if(val > T(0))
270 return round_t<I, T, cstyle, downward>::round(val, epsilon);
271 else return round_t<I, T, cstyle, upward>::round(val, epsilon);
272 }
273 };
274 template<class I, class T, CmpStyle cstyle>
275 struct round_t<I, T, cstyle, towardInf> {
276 static I
277 round(const T &val,
279 if(val > T(0))
280 return round_t<I, T, cstyle, upward>::round(val, epsilon);
281 else return round_t<I, T, cstyle, downward>::round(val, epsilon);
282 }
283 };
284 template<class I, class T, CmpStyle cstyle, RoundingStyle rstyle>
285 struct round_t<std::vector<I>, std::vector<T>, cstyle, rstyle> {
286 static std::vector<I>
287 round(const T &val,
289 unsigned int size = val.size();
290 std::vector<I> res(size);
291 for(unsigned int i = 0; i < size; ++i)
292 res[i] = round_t<I, T, cstyle, rstyle>::round(val[i], epsilon);
293 return res;
294 }
295 };
296 template<class I, class T, int n, CmpStyle cstyle, RoundingStyle rstyle>
297 struct round_t<Dune::FieldVector<I, n>, Dune::FieldVector<T, n>, cstyle, rstyle> {
299 round(const T &val,
302 for(int i = 0; i < n; ++i)
303 res[i] = round_t<I, T, cstyle, rstyle>::round(val[i], epsilon);
304 return res;
305 }
306 };
307 } // end namespace Impl
308 template<class I, class T, CmpStyle cstyle, RoundingStyle rstyle>
309 I round(const T &val, typename EpsilonType<T>::Type epsilon /*= DefaultEpsilon<T, cstyle>::value()*/)
310 {
311 return Impl::round_t<I, T, cstyle, rstyle>::round(val, epsilon);
312 }
313 template<class I, class T, CmpStyle cstyle>
314 I round(const T &val, typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T, cstyle>::value())
315 {
316 return round<I, T, cstyle, defaultRoundingStyle>(val, epsilon);
317 }
318 template<class I, class T, RoundingStyle rstyle>
319 I round(const T &val, typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T, defaultCmpStyle>::value())
320 {
321 return round<I, T, defaultCmpStyle, rstyle>(val, epsilon);
322 }
323 template<class I, class T>
325 {
326 return round<I, T, defaultCmpStyle>(val, epsilon);
327 }
328
329 // truncation
330 namespace Impl {
331 template<class I, class T, CmpStyle cstyle = defaultCmpStyle, RoundingStyle rstyle = defaultRoundingStyle>
332 struct trunc_t;
333 template<class I, class T, CmpStyle cstyle>
334 struct trunc_t<I, T, cstyle, downward> {
335 static I
336 trunc(const T &val,
338 // this should be optimized away unless needed
340 // make sure this works for all useful cases even if I is an unsigned type
341 if(eq<T, cstyle>(val, T(0), epsilon)) return I(0);
342 // first get an approximation
343 I lower = I(val); // now |val-lower| < 1
344 // make sure we're really lower in case the cast truncated to an unexpected direction
345 if(T(lower) > val) lower--; // now val-lower < 1
346 // check whether lower + 1 is approximately val
347 if(eq<T, cstyle>(T(lower+1), val, epsilon))
348 return lower+1;
349 else return lower;
350 }
351 };
352 template<class I, class T, CmpStyle cstyle>
353 struct trunc_t<I, T, cstyle, upward> {
354 static I
355 trunc(const T &val,
357 I upper = trunc_t<I, T, cstyle, downward>::trunc(val, epsilon);
358 if(ne<T, cstyle>(T(upper), val, epsilon)) ++upper;
359 return upper;
360 }
361 };
362 template<class I, class T, CmpStyle cstyle>
363 struct trunc_t<I, T, cstyle, towardZero> {
364 static I
365 trunc(const T &val,
367 if(val > T(0)) return trunc_t<I, T, cstyle, downward>::trunc(val, epsilon);
368 else return trunc_t<I, T, cstyle, upward>::trunc(val, epsilon);
369 }
370 };
371 template<class I, class T, CmpStyle cstyle>
372 struct trunc_t<I, T, cstyle, towardInf> {
373 static I
374 trunc(const T &val,
376 if(val > T(0)) return trunc_t<I, T, cstyle, upward>::trunc(val, epsilon);
377 else return trunc_t<I, T, cstyle, downward>::trunc(val, epsilon);
378 }
379 };
380 template<class I, class T, CmpStyle cstyle, RoundingStyle rstyle>
381 struct trunc_t<std::vector<I>, std::vector<T>, cstyle, rstyle> {
382 static std::vector<I>
383 trunc(const std::vector<T> &val,
385 unsigned int size = val.size();
386 std::vector<I> res(size);
387 for(unsigned int i = 0; i < size; ++i)
388 res[i] = trunc_t<I, T, cstyle, rstyle>::trunc(val[i], epsilon);
389 return res;
390 }
391 };
392 template<class I, class T, int n, CmpStyle cstyle, RoundingStyle rstyle>
393 struct trunc_t<Dune::FieldVector<I, n>, Dune::FieldVector<T, n>, cstyle, rstyle> {
398 for(int i = 0; i < n; ++i)
399 res[i] = trunc_t<I, T, cstyle, rstyle>::trunc(val[i], epsilon);
400 return res;
401 }
402 };
403 } // namespace Impl
404 template<class I, class T, CmpStyle cstyle, RoundingStyle rstyle>
405 I trunc(const T &val, typename EpsilonType<T>::Type epsilon /*= DefaultEpsilon<T, cstyle>::value()*/)
406 {
407 return Impl::trunc_t<I, T, cstyle, rstyle>::trunc(val, epsilon);
408 }
409 template<class I, class T, CmpStyle cstyle>
410 I trunc(const T &val, typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T, cstyle>::value())
411 {
412 return trunc<I, T, cstyle, defaultRoundingStyle>(val, epsilon);
413 }
414 template<class I, class T, RoundingStyle rstyle>
415 I trunc(const T &val, typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T, defaultCmpStyle>::value())
416 {
417 return trunc<I, T, defaultCmpStyle, rstyle>(val, epsilon);
418 }
419 template<class I, class T>
421 {
422 return trunc<I, T, defaultCmpStyle>(val, epsilon);
423 }
424 } //namespace Dune
425
426 // oo interface
427 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
430
431
432 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
435 {
436 return epsilon_;
437 }
438
439 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
440 void
442 {
443 epsilon_ = epsilon__;
444 }
445
446
447 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
449 eq(const ValueType &first, const ValueType &second) const
450 {
451 return Dune::FloatCmp::eq<ValueType, cstyle>(first, second, epsilon_);
452 }
453
454 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
456 ne(const ValueType &first, const ValueType &second) const
457 {
458 return Dune::FloatCmp::ne<ValueType, cstyle>(first, second, epsilon_);
459 }
460
461 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
463 gt(const ValueType &first, const ValueType &second) const
464 {
465 return Dune::FloatCmp::gt<ValueType, cstyle>(first, second, epsilon_);
466 }
467
468 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
470 lt(const ValueType &first, const ValueType &second) const
471 {
472 return Dune::FloatCmp::lt<ValueType, cstyle>(first, second, epsilon_);
473 }
474
475 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
477 ge(const ValueType &first, const ValueType &second) const
478 {
479 return Dune::FloatCmp::ge<ValueType, cstyle>(first, second, epsilon_);
480 }
481
482 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
484 le(const ValueType &first, const ValueType &second) const
485 {
486 return Dune::FloatCmp::le<ValueType, cstyle>(first, second, epsilon_);
487 }
488
489
490 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
491 template<class I>
493 round(const ValueType &val) const
494 {
495 return Dune::FloatCmp::round<I, ValueType, cstyle, rstyle_>(val, epsilon_);
496 }
497
498 template<class T, FloatCmp::CmpStyle cstyle_, FloatCmp::RoundingStyle rstyle_>
499 template<class I>
501 trunc(const ValueType &val) const
502 {
503 return Dune::FloatCmp::trunc<I, ValueType, cstyle, rstyle_>(val, epsilon_);
504 }
505
506} //namespace Dune
Various ways to compare floating-point numbers.
Implements a vector constructed from a given type representing a field and a compile-time given size.
bool ne(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test for inequality using epsilon
Definition float_cmp.cc:149
bool eq(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test for equality using epsilon
Definition float_cmp.cc:142
I round(const T &val, typename EpsilonType< T >::Type epsilon)
round using epsilon
Definition float_cmp.cc:309
I trunc(const T &val, typename EpsilonType< T >::Type epsilon)
truncate using epsilon
Definition float_cmp.cc:405
bool lt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test if first lesser than second
Definition float_cmp.cc:163
bool gt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test if first greater than second
Definition float_cmp.cc:156
bool ge(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test if first greater or equal second
Definition float_cmp.cc:170
bool le(const T &first, const T &second, typename EpsilonType< T >::Type epsilon)
test if first lesser or equal second
Definition float_cmp.cc:177
@ relativeStrong
|a-b|/|a| <= epsilon && |a-b|/|b| <= epsilon
Definition float_cmp.hh:106
@ relativeWeak
|a-b|/|a| <= epsilon || |a-b|/|b| <= epsilon
Definition float_cmp.hh:104
@ absolute
|a-b| <= epsilon
Definition float_cmp.hh:108
@ towardZero
always round toward 0
Definition float_cmp.hh:116
@ towardInf
always round away from 0
Definition float_cmp.hh:118
@ upward
round toward
Definition float_cmp.hh:122
@ downward
round toward
Definition float_cmp.hh:120
STL namespace.
Dune namespace.
Definition alignedallocator.hh:11
vector space out of a tensor product of fields.
Definition fvector.hh:95
Mapping of value type to epsilon type.
Definition float_cmp.cc:21
T Type
The epsilon type corresponding to value type T.
Definition float_cmp.cc:23
EpsilonType< T >::Type Type
The epsilon type corresponding to value type std::vector<T, A>
Definition float_cmp.cc:34
EpsilonType< T >::Type Type
The epsilon type corresponding to value type Dune::FieldVector<T, n>
Definition float_cmp.cc:45
static EpsilonType< T >::Type value()
Definition float_cmp.cc:51
static EpsilonType< T >::Type value()
Definition float_cmp.cc:56
static EpsilonType< T >::Type value()
Definition float_cmp.cc:61
mapping from a value type and a compare style to a default epsilon
Definition float_cmp.hh:136
static EpsilonType< T >::Type value()
Returns the default epsilon for the given value type and compare style.
bool le(const ValueType &first, const ValueType &second) const
test if first lesser or equal second
Definition float_cmp.cc:484
FloatCmpOps(EpsilonType epsilon=DefaultEpsilon::value())
construct an operations object
Definition float_cmp.cc:429
bool eq(const ValueType &first, const ValueType &second) const
test for equality using epsilon
Definition float_cmp.cc:449
bool lt(const ValueType &first, const ValueType &second) const
test if first lesser than second
Definition float_cmp.cc:470
bool ge(const ValueType &first, const ValueType &second) const
test if first greater or equal second
Definition float_cmp.cc:477
FloatCmp::EpsilonType< T >::Type EpsilonType
Type of the epsilon.
Definition float_cmp.hh:302
bool ne(const ValueType &first, const ValueType &second) const
test for inequality using epsilon
Definition float_cmp.cc:456
T ValueType
Type of the values to compare.
Definition float_cmp.hh:297
EpsilonType epsilon() const
return the current epsilon
Definition float_cmp.cc:434
I round(const ValueType &val) const
round using epsilon
Definition float_cmp.cc:493
I trunc(const ValueType &val) const
truncate using epsilon
Definition float_cmp.cc:501
bool gt(const ValueType &first, const ValueType &second) const
test if first greater than second
Definition float_cmp.cc:463
T max(T... args)
T min(T... args)
T size(T... args)