Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
TestCompareFloatingPoint.cpp
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3  Copyright (C) 2003-2009 (see file CONTACT for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8  BIAS is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation; either version 2.1 of the License, or
11  (at your option) any later version.
12 
13  BIAS is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License
19  along with BIAS; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
21 
22 /**
23  @file TestCompareFloatingPoint.cpp
24  @relates CompareFloatingPoint
25  @brief Test comparison of floating point numbers
26  @ingroup g_tests
27  @author MIP
28 */
29 
30 #include <Base/Common/W32Compat.hh>
31 #include <Base/Debug/Error.hh>
32 #include <Base/Common/CompareFloatingPoint.hh>
33 
34 #include <vector>
35 #include <limits>
36 #include <map>
37 #include <iostream>
38 #include <iomanip>
39 
40 using namespace std;
41 using namespace BIAS;
42 
43 enum ERelation { LESS, LESS_EQUAL, EQUAL, GREATER_EQUAL, GREATER };
44 
45 ostream& operator<<(ostream& os, const enum ERelation& r)
46 {
47  switch (r){
48  case LESS: os << "<"; break;
49  case LESS_EQUAL: os << "<="; break;
50  case EQUAL: os << "=="; break;
51  case GREATER: os << ">"; break;
52  case GREATER_EQUAL: os << ">="; break;
53  }
54  return os;
55 }
56 
57 /**\cond HIDDEN_SYMBOLS
58  * @relates CompareFloatingPoint */
59 template <class T>
60 class TestValuePair
61 {
62 public:
63  TestValuePair(const T l, const ERelation rel, const T r, const T eps)
64  : left(l), right(r), epsilon(eps), relation(rel)
65  { if (rel==LESS_EQUAL || rel==GREATER_EQUAL) { BIASABORT; } }
66 
67  /// the two values
68  T left, right;
69  /// epsilon for comparison
70  T epsilon;
71  /// the true relation, i.e. GREATER, LESS or EQUAL
72  /// the true relation cannot be GREATER_EQUAL or LESS_EQUAL
73  ERelation relation;
74 };
75 /** \endcond */
76 
77 /** @relates CompareFloatingPoint */
78 template <class T>
79 void GenTestValues(vector<TestValuePair<T> >& tv)
80 {
81 #if defined(max) || defined(min)
82 # undef max
83 # undef min
84  const T mini = numeric_limits<T>::min();
85  const T maxi = numeric_limits<T>::max();
86 
87 # define max(a,b) ((a) >= (b) ? (a) : (b))
88 # define min(a,b) ((a) <= (b) ? (a) : (b))
89 #else
90  const T mini = numeric_limits<T>::min();
91  const T maxi = numeric_limits<T>::max();
92 #endif
93  const T eps = numeric_limits<T>::epsilon();
94  // the true
95  tv.clear();
96  tv.push_back(TestValuePair<T>(0.0, EQUAL, 0.0, 0.0));
97  tv.push_back(TestValuePair<T>(1.0, EQUAL, ((T)1.0)+eps, eps*((T)2.0)));
98  tv.push_back(TestValuePair<T>(mini, LESS, mini*((T)2.0), eps));
99  tv.push_back(TestValuePair<T>(mini, EQUAL, mini, eps));
100  tv.push_back(TestValuePair<T>(0.0, EQUAL, mini, mini*((T)2.0)));
101  tv.push_back(TestValuePair<T>(mini, EQUAL, 0.0, mini*((T)2)));
102  tv.push_back(TestValuePair<T>(((T)1e-10), EQUAL,
103  ((T)1e-10)+((T)1e-18), ((T)1e-7)));
104  tv.push_back(TestValuePair<T>(0.0, EQUAL, 0.0, mini));
105  tv.push_back(TestValuePair<T>(5.0, LESS, ((T)5.0)+eps*((T)10.0), eps));
106  tv.push_back(TestValuePair<T>(1.0, EQUAL, 1.0, eps));
107  tv.push_back(TestValuePair<T>(0.0, LESS, 1.0, eps));
108  tv.push_back(TestValuePair<T>(0.0, LESS, maxi, eps));
109  tv.push_back(TestValuePair<T>(maxi, GREATER, 0.0, eps));
110  tv.push_back(TestValuePair<T>(maxi, GREATER, 100.0, eps));
111  tv.push_back(TestValuePair<T>(maxi, GREATER, -maxi, eps));
112  tv.push_back(TestValuePair<T>(-maxi, LESS, maxi, eps));
113 }
114 
115 /// builds the map of expected results for the different comparison functions
116 void BuildMap(map<ERelation, map<ERelation, bool> >& m)
117 {
118  // m[true relation][tested relation]
119 
120  m[EQUAL][EQUAL] = true;
121  m[EQUAL][LESS] = false;
122  m[EQUAL][GREATER] = false;
123  m[EQUAL][LESS_EQUAL] = true;
124  m[EQUAL][GREATER_EQUAL] = true;
125 
126  m[LESS][EQUAL] = false;
127  m[LESS][LESS] = true;
128  m[LESS][GREATER] = false;
129  m[LESS][LESS_EQUAL] = true;
130  m[LESS][GREATER_EQUAL] = false;
131 
132  m[GREATER][EQUAL] = false;
133  m[GREATER][LESS] = false;
134  m[GREATER][GREATER] = true;
135  m[GREATER][LESS_EQUAL] = false;
136  m[GREATER][GREATER_EQUAL] = true;
137 }
138 
139 /** @relates CompareFloatingPoint */
140 template <class T>
141 void Test(const TestValuePair<T>& t)
142 {
143  if (t.relation==LESS_EQUAL || t.relation == GREATER_EQUAL){
144  BIASERR("true relation cannot be greater equal or less equal!");
145  BIASABORT;
146  }
147 
148  // m[true relation][tested relation]
149  static map<ERelation, map<ERelation, bool> > exp_res;
150  if (exp_res.empty()) BuildMap(exp_res);
151 
152  const bool debug = false;
153  if (debug) cout << "\nepsilon: "<<setprecision(30) << t.epsilon
154  << " true relation: "<< setprecision(30) <<t.left
155  <<" "<<t.relation<<" "<<setprecision(30) <<t.right<<endl;
156  bool res;
157  res = Equal(t.left, t.right, t.epsilon);
158  if (debug) cout << " "<<setprecision(30) << t.left <<" == "<<setprecision(30)
159  << t.right << " = "<<boolalpha<<res<<endl;
160  if (res != exp_res[t.relation][EQUAL]) {
161  BIASERR("left: "<<t.left<<" right: "<<t.right<<" true relation: "
162  <<t.relation<<" expected result: "<<boolalpha
163  <<exp_res[t.relation][EQUAL]
164  <<" result: "<<boolalpha<<res<<endl);
165  cout << "fabs(left-right): "<<fabs(t.left-t.right)<<endl
166  << "eps * fabs(right): "<<t.epsilon * fabs(t.right)<<endl
167  << "eps * fabs(left): "<<t.epsilon * fabs(t.left)<<endl
168  << "right!=0.: "<<boolalpha<<(t.right!=0.) <<endl
169  << "left!=0.: "<<boolalpha<<(t.left!=0.) <<endl
170  << "right==0.: "<<boolalpha<<(t.right==0.) <<endl
171  << "left==0.: "<<boolalpha<<(t.left==0.) <<endl;
172  if (!(t.right==0.))
173  cout << "fabs(left-right) / fabs(right): "
174  <<fabs(t.left-t.right) / fabs(t.right)<<endl;
175  if (!(t.left==0.))
176  cout << "fabs(left-right) / fabs(left): "
177  <<fabs(t.left-t.right) / fabs(t.left)<<endl;
178  BIASABORT;
179  }
180 
181  res = Less(t.left, t.right, t.epsilon);
182  if (debug) cout << " "<<setprecision(30) << t.left <<" < "<<setprecision(30)
183  << t.right << " = "<<boolalpha<<res<<endl;
184  if (res != exp_res[t.relation][LESS]) {
185  BIASERR("left: "<<t.left<<" right: "<<t.right<<" true relation: "
186  <<t.relation<<" expected result: "<<boolalpha
187  <<exp_res[t.relation][LESS]
188  <<" result: "<<boolalpha<<res<<endl);
189  BIASABORT;
190  }
191 
192 
193  res = LessEqual(t.left, t.right, t.epsilon);
194  if (debug) cout << " "<<setprecision(30) << t.left <<" <= "<<setprecision(30)
195  << t.right << " = "<<boolalpha<<res<<endl;
196  if (res != exp_res[t.relation][LESS_EQUAL]) {
197  BIASERR("left: "<<t.left<<" right: "<<t.right<<" true relation: "
198  <<t.relation<<" expected result: "<<boolalpha
199  <<exp_res[t.relation][LESS_EQUAL]
200  <<" result: "<<boolalpha<<res<<endl);
201  BIASABORT;
202  }
203 
204  res = Greater(t.left, t.right, t.epsilon);
205  if (debug) cout << " "<<setprecision(30) << t.left <<" > "<<setprecision(30)
206  << t.right << " = "<<boolalpha<<res<<endl;
207  if (res != exp_res[t.relation][GREATER]) {
208  BIASERR("left: "<<t.left<<" right: "<<t.right<<" true relation: "
209  <<t.relation<<" expected result: "<<boolalpha
210  <<exp_res[t.relation][GREATER]
211  <<" result: "<<boolalpha<<res<<endl);
212  BIASABORT;
213  }
214 
215  res = GreaterEqual(t.left, t.right, t.epsilon);
216  if (debug) cout << " "<<setprecision(30) << t.left <<" >= "<<setprecision(30)
217  << t.right << " = "<<boolalpha<<res<<endl;
218  if (res != exp_res[t.relation][GREATER_EQUAL]) {
219  BIASERR("left: "<<t.left<<" right: "<<t.right<<" true relation: "
220  <<t.relation<<" expected result: "<<boolalpha
221  <<exp_res[t.relation][GREATER_EQUAL]
222  <<" result: "<<boolalpha<<res<<endl);
223  BIASABORT;
224  }
225 
226  /// there are 3 true relations and hence the size of exp_res must be 3
227  BIASASSERT(exp_res.size()==3u);
228 }
229 
230 /** @relates CompareFloatingPoint
231  @author woelk 02/2008 (c) www.vision-n.de */
232 int main(int argc, char *argv[])
233 {
234  // test float
235  vector<TestValuePair<float> > tvf;
236  GenTestValues(tvf);
237 
238  vector<TestValuePair<float> >::const_iterator itf;
239  for (itf=tvf.begin(); itf!=tvf.end(); itf++){
240  Test(*itf);
241  }
242 
243  // test double
244  vector<TestValuePair<double> > tvd;
245  GenTestValues(tvd);
246 
247  vector<TestValuePair<double> >::const_iterator itd;
248  for (itd=tvd.begin(); itd!=tvd.end(); itd++){
249  Test(*itd);
250  }
251 
252 
253  return 0;
254 }
bool Less(const T left, const T right, const T eps=std::numeric_limits< T >::epsilon())
comparison function for floating point values
bool Greater(const T left, const T right, const T eps=std::numeric_limits< T >::epsilon())
comparison function for floating point values
bool GreaterEqual(const T left, const T right, const T eps=std::numeric_limits< T >::epsilon())
comparison function for floating point values
bool LessEqual(const T left, const T right, const T eps=std::numeric_limits< T >::epsilon())
comparison function for floating point values
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...