tut logo

tut_fpt.hpp Source File


tut_fpt.hpp
1 
6 #ifndef TUT_Float_H_GUARD
7 #define TUT_Float_H_GUARD
8 
9 #include <limits>
10 #include <iostream>
11 
12 namespace tut
13 {
14  namespace detail
15  {
16  template<bool Predicate, typename Then, typename Else>
17  struct If
18  {
19  typedef Else type;
20  };
21 
22  template<typename Then, typename Else>
23  struct If<true,Then,Else>
24  {
25  typedef Then type;
26  };
27 
28  template<typename T>
29  struct fpt_traits
30  {
32  static const StdNumericLimitsNotAvailable static_check[ std::numeric_limits<T>::is_specialized ];
33 
34  static const T zero;
35 
37  double,
38  T>::type Result;
39 
40  static T abs(const T &arg)
41  {
42  if(arg < zero)
43  return zero - arg;
44  else
45  return arg;
46  }
47 
48  static T sig(const T &arg)
49  {
50  if(arg < zero)
51  return -1;
52  else
53  return 1;
54  }
55 
56  static inline Result div(const Result &number, const T &divisor)
57  {
58  static_cast<void>(static_check);
59 
60  if(number == zero && divisor == zero)
61  return std::numeric_limits<Result>::quiet_NaN();
62 
63  if(number == zero)
64  return zero;
65 
66  if(divisor == zero)
67  return sig(number) * std::numeric_limits<Result>::infinity();
68 
69  assert(zero < number);
70  assert(zero < divisor);
71 
72  // Avoid underflow
73  if(static_cast<T>(1) < abs(divisor))
74  {
75  // number / divisor < min <=> number < min * divisor
76  if( abs(number) < abs(divisor) * std::numeric_limits<T>::min())
77  {
78  return sig(divisor) * sig(number) * std::numeric_limits<T>::min();
79  }
80  }
81 
82  // Avoid overflow
83  if( abs(divisor) < static_cast<T>(1))
84  {
85  // number / divisor > max <=> number > max * divisor
86  if( abs(divisor) * std::numeric_limits<T>::max() < abs(number))
87  {
88  return sig(divisor) * sig(number) * std::numeric_limits<T>::max();
89  }
90  }
91 
92  return number / divisor;
93  }
94  };
95 
96  template<typename T>
97  const typename fpt_traits<T>::StdNumericLimitsNotAvailable
98  fpt_traits<T>::static_check[ std::numeric_limits<T>::is_specialized ] = { {} };
99 
100  template<typename T>
101  const T fpt_traits<T>::zero = static_cast<T>(0);
102 
103  template<typename T, typename U>
104  bool check_tolerance(T actual, T expected, U fraction)
105  {
106  typename fpt_traits<T>::Result diff = fpt_traits<T>::div( fpt_traits<T>::abs( expected - actual ),
107  fpt_traits<T>::abs( expected ) );
108 
109  return (diff == fraction) || (diff < fraction);
110  }
111 
112  } // namespace detail
113 
114  template<typename T, typename U>
115  void ensure_close(const char* msg, const T& actual, const T& expected, const U& tolerance )
116  {
117  typedef detail::fpt_traits<U> Traits;
118 
119  typename Traits::Result fraction = Traits::div( Traits::abs(static_cast<typename Traits::Result>(tolerance)),
120  static_cast<typename Traits::Result>(100) );
121  if( !detail::check_tolerance(actual, expected, fraction) )
122  {
123  std::ostringstream ss;
124  ss << ( msg ? msg : "" )
125  << ( msg ? ": " : "" )
126  << "expected `"
127  << expected
128  << "` and actual `"
129  << actual
130  << "` differ more than "
131  << tolerance
132  << "%";
133  throw failure( ss.str().c_str() );
134  }
135  }
136 
137  template<typename T, typename Tolerance>
138  void ensure_close(const T& actual, const T& expected, const Tolerance& tolerance )
139  {
140  ensure_close( 0, actual, expected, tolerance );
141  }
142 
143  template<typename T, typename U>
144  void ensure_close_fraction(const char* msg, const T& actual, const T& expected, const U& fraction)
145  {
146  typedef char StdNumericLimitsNotAvailable;
147  const StdNumericLimitsNotAvailable static_check[ std::numeric_limits<U>::is_specialized ] = { 0 };
148  static_cast<void>(static_check);
149 
150  typedef typename detail::If<std::numeric_limits<U>::is_integer,
151  double,
152  U>::type Tolerance;
153 
154  if( !detail::check_tolerance(actual, expected, fraction) )
155  {
156  std::ostringstream ss;
157  ss << ( msg ? msg : "" )
158  << ( msg ? ": " : "" )
159  << "expected `"
160  << expected
161  << "` and actual `"
162  << actual
163  << "` differ more than fraction `"
164  << fraction
165  << "`";
166  throw failure( ss.str().c_str() );
167  }
168  }
169 
170  template<typename T>
171  void ensure_close_fraction( const char* msg, const T& actual, const T& expected, const int& tolerance )
172  {
173  ensure_close(msg, actual, expected, double(tolerance));
174  }
175 
176  template< typename T, typename Tolerance>
177  void ensure_close_fraction(const T& actual, const T& expected, const Tolerance& fraction)
178  {
179  ensure_close_fraction( 0, actual, expected, fraction );
180  }
181 
182 } // namespace tut
183 
184 #endif
185 
Definition: tut_fpt.hpp:17
Definition: tut_fpt.hpp:29

All Rights Reserved. Generated on Wed Dec 18 2013 11:19:52 for TUT by doxygen 1.8.5