• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* boost limits_test.cpp   test your <limits> file for important
2  *
3  * Copyright Jens Maurer 2000
4  * Permission to use, copy, modify, sell, and distribute this software
5  * is hereby granted without fee provided that the above copyright notice
6  * appears in all copies and that both that copyright notice and this
7  * permission notice appear in supporting documentation,
8  *
9  * Jens Maurer makes no representations about the suitability of this
10  * software for any purpose. It is provided "as is" without express or
11  * implied warranty.
12  *
13  */
14 
15 #include <limits>
16 //#include <sstream>
17 
18 #include "cppunit/cppunit_proxy.h"
19 
20 #if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
21 using namespace std;
22 #endif
23 
24 //
25 // TestCase class
26 //
27 class LimitTest : public CPPUNIT_NS::TestCase
28 {
29   CPPUNIT_TEST_SUITE(LimitTest);
30 #  if defined (__BORLANDC__)
31   /* Ignore FPU exceptions, set FPU precision to 64 bits */
32   unsigned int _float_control_word = _control87(0, 0);
33   _control87(PC_64|MCW_EM|IC_AFFINE, MCW_PC|MCW_EM|MCW_IC);
34 #  endif
35   CPPUNIT_TEST(test);
36   CPPUNIT_TEST(qnan_test);
37 #  if defined (__BORLANDC__)
38   /* Reset floating point control word */
39   _clear87();
40   _control87(_float_control_word, MCW_PC|MCW_EM|MCW_IC);
41 #  endif
42   CPPUNIT_TEST_SUITE_END();
43 
44 protected:
45   void test();
46   void qnan_test();
47 };
48 
49 CPPUNIT_TEST_SUITE_REGISTRATION(LimitTest);
50 
51 #if defined (STLPORT) && defined (_STLP_STATIC_CONST_INIT_BUG)
52 #  define CHECK_COND(X) if (!(X))  { CPPUNIT_MESSAGE(#X); return false; }
53 #else
54 //This version force to have external linkage on static constant which might
55 //reveal that _STLP_NO_STATIC_CONST_DEFINITION should be commented.
check_cond(const bool & cond)56 bool check_cond(const bool& cond) { return cond; }
57 #  define CHECK_COND(X) if (!check_cond(X)) { CPPUNIT_MESSAGE(#X); return false; }
58 #endif
59 
valid_sign_info(bool,bool)60 bool valid_sign_info(bool, bool)
61 { return true; }
62 
63 template <class _Tp>
valid_sign_info(bool limit_is_signed,const _Tp &)64 bool valid_sign_info(bool limit_is_signed, const _Tp &) {
65   return (limit_is_signed && _Tp(-1) < 0) ||
66          (!limit_is_signed && _Tp(-1) > 0);
67 }
68 
69 template <class _Tp>
test_integral_limits_base(const _Tp &,bool unknown_sign=true,bool is_signed=true)70 bool test_integral_limits_base(const _Tp &, bool unknown_sign = true, bool is_signed = true) {
71   typedef numeric_limits<_Tp> lim;
72 
73   CHECK_COND(lim::is_specialized);
74   CHECK_COND(lim::is_exact);
75   CHECK_COND(lim::is_integer);
76   CHECK_COND(!lim::is_iec559);
77   CHECK_COND(lim::min() < lim::max());
78   CHECK_COND((unknown_sign && ((lim::is_signed && (lim::min() != 0)) || (!lim::is_signed && (lim::min() == 0)))) ||
79              (!unknown_sign && ((lim::is_signed && is_signed) || (!lim::is_signed && !is_signed))));
80 
81   if (unknown_sign) {
82     CHECK_COND(valid_sign_info(lim::is_signed, _Tp()));
83   }
84   return true;
85 }
86 
87 template <class _Tp>
test_integral_limits(const _Tp & val,bool unknown_sign=true,bool is_signed=true)88 bool test_integral_limits(const _Tp &val, bool unknown_sign = true, bool is_signed = true) {
89   if (!test_integral_limits_base(val, unknown_sign, is_signed))
90     return false;
91 
92   typedef numeric_limits<_Tp> lim;
93 
94   CHECK_COND(lim::is_modulo);
95 
96   if (lim::is_bounded ||
97      (!lim::is_bounded && !lim::is_signed)) {
98     _Tp tmp = lim::min();
99     CHECK_COND( --tmp > lim::min() );
100   }
101 
102   if (lim::is_bounded) {
103     _Tp tmp = lim::max();
104     CHECK_COND( ++tmp < lim::max() );
105   }
106 
107   return true;
108 }
109 
110 template <class _Tp>
test_signed_integral_limits(const _Tp & __val)111 bool test_signed_integral_limits(const _Tp &__val) {
112   return test_integral_limits(__val, false, true);
113 }
114 template <class _Tp>
test_unsigned_integral_limits(const _Tp & __val)115 bool test_unsigned_integral_limits(const _Tp &__val) {
116   return test_integral_limits(__val, false, false);
117 }
118 
119 template <class _Tp>
test_float_values(_Tp lhs,_Tp rhs)120 bool test_float_values(_Tp lhs, _Tp rhs)
121 { return lhs == rhs; }
122 
123 template <class _Tp>
test_float_limits(const _Tp &)124 bool test_float_limits(const _Tp &) {
125   typedef numeric_limits<_Tp> lim;
126   CHECK_COND(lim::is_specialized);
127   CHECK_COND(!lim::is_modulo);
128   CHECK_COND(!lim::is_integer);
129   CHECK_COND(lim::is_signed);
130 
131   CHECK_COND(lim::max() > 1000);
132   CHECK_COND(lim::min() > 0);
133   CHECK_COND(lim::min() < 0.001);
134   CHECK_COND(lim::epsilon() > 0);
135 
136   if (lim::is_iec559) {
137     CHECK_COND(lim::has_infinity);
138     CHECK_COND(lim::has_quiet_NaN);
139     CHECK_COND(lim::has_signaling_NaN);
140     CHECK_COND(lim::has_denorm == denorm_present);
141   }
142 
143   if (lim::has_denorm == denorm_absent) {
144     CHECK_COND(lim::denorm_min() == lim::min());
145     _Tp tmp = lim::min();
146     tmp /= 2;
147     if (tmp > 0 && tmp < lim::min()) {
148       // has_denorm could be denorm_present
149       CPPUNIT_MESSAGE("It looks like your compiler/platform supports denormalized floating point representation.");
150     }
151   }
152   else if (lim::has_denorm == denorm_present) {
153     CHECK_COND(lim::denorm_min() > 0);
154     CHECK_COND(lim::denorm_min() < lim::min());
155 
156     _Tp tmp = lim::min();
157     while (tmp != 0) {
158       _Tp old_tmp = tmp;
159       tmp /= 2;
160       CHECK_COND(tmp < old_tmp);
161       CHECK_COND(tmp >= lim::denorm_min() || tmp == (_Tp)0);
162       //ostringstream str;
163       //str << "denorm_min = " << lim::denorm_min() << ", tmp = " << tmp;
164       //CPPUNIT_MESSAGE(str.str().c_str());
165     }
166   }
167 
168   if (lim::has_infinity) {
169     const _Tp infinity = lim::infinity();
170     /* Make sure those values are not 0 or similar nonsense.
171      * Infinity must compare as if larger than the maximum representable value. */
172 
173     _Tp val = lim::max();
174     val *= 2;
175 
176     /* We use test_float_values because without it some compilers (gcc) perform weird
177      * optimization on the test giving unexpected result. */
178     CHECK_COND(test_float_values(val, infinity));
179 
180     /*
181     ostringstream str;
182     str << "lim::max() = " << lim::max() << ", val = " << val << ", infinity = " << infinity;
183     CPPUNIT_MESSAGE( str.str().c_str() );
184     str.str(string());
185     str << "sizeof(_Tp) = " << sizeof(_Tp);
186     CPPUNIT_MESSAGE( str.str().c_str() );
187     if (sizeof(_Tp) == 4) {
188       str.str(string());
189       str << "val in hexa: " << showbase << hex << *((const unsigned int*)&val);
190       str << ", infinity in hexa: " << showbase << hex << *((const unsigned int*)&infinity);
191     }
192 #if defined (_STLP_LONG_LONG)
193     else if (sizeof(_Tp) == sizeof(_STLP_LONG_LONG)) {
194       str.str(string());
195       str << "val in hexa: " << showbase << hex << *((const unsigned _STLP_LONG_LONG*)&val);
196       str << ", infinity in hexa: " << showbase << hex << *((const unsigned _STLP_LONG_LONG*)&infinity);
197     }
198 #endif
199     else {
200       str.str(string());
201       str << "val: ";
202       for (int i = 0; i != sizeof(_Tp) /  sizeof(unsigned short); ++i) {
203         if (i != 0) str << ' ';
204         str << showbase << hex << setw(4) << setfill('0') << *((const unsigned short*)&val + i);
205       }
206       str << ", infinity: ";
207       for (int i = 0; i != sizeof(_Tp) /  sizeof(unsigned short); ++i) {
208         if (i != 0) str << ' ';
209         str << showbase << hex << setw(4) << setfill('0') << *((const unsigned short*)&infinity + i);
210       }
211     }
212     CPPUNIT_MESSAGE( str.str().c_str() );
213     str.str(string());
214     str << dec;
215     str << "lim::digits = " << lim::digits << ", lim::digits10 = " << lim::digits10 << endl;
216     str << "lim::min_exponent = " << lim::min_exponent << ", lim::min_exponent10 = " << lim::min_exponent10 << endl;
217     str << "lim::max_exponent = " << lim::max_exponent << ", lim::max_exponent10 = " << lim::max_exponent10 << endl;
218     CPPUNIT_MESSAGE( str.str().c_str() );
219     */
220 
221     CHECK_COND(infinity == infinity);
222     CHECK_COND(infinity > lim::max());
223     CHECK_COND(-infinity < -lim::max());
224   }
225 
226   return true;
227 }
228 
229 //float generate_nan(float f) {
230 //  return 0.0f / f;
231 //}
232 template <class _Tp>
test_qnan(const _Tp &)233 bool test_qnan(const _Tp &) {
234   typedef numeric_limits<_Tp> lim;
235   if (lim::has_quiet_NaN) {
236     const _Tp qnan = lim::quiet_NaN();
237 
238     //if (sizeof(_Tp) == 4) {
239     //  ostringstream str;
240     //  str << "qnan " << qnan << ", in hexa: " << showbase << hex << *((unsigned int*)&qnan);
241     //  CPPUNIT_MESSAGE( str.str().c_str() );
242     //  str.str("");
243     //  float val = generate_nan(0.0f);
244     //  str << "val " << val << ", in hexa: " << showbase << hex << *((unsigned int*)&val);
245     //  CPPUNIT_MESSAGE( str.str().c_str() );
246     //  str.str("");
247     //  val = -qnan;
248     //  str << "-qnan " << val << ", in hexa: " << showbase << hex << *((unsigned int*)&val);
249     //  CPPUNIT_MESSAGE( str.str().c_str() );
250     //}
251     /* NaNs shall always compare "false" when compared for equality
252     * If one of these fail, your compiler may be optimizing incorrectly,
253     * or the STLport is incorrectly configured.
254     */
255     CHECK_COND(! (qnan == 42));
256     CHECK_COND(! (qnan == qnan));
257     CHECK_COND(qnan != 42);
258     CHECK_COND(qnan != qnan);
259 
260     /* The following tests may cause arithmetic traps.
261     * CHECK_COND(! (qnan < 42));
262     * CHECK_COND(! (qnan > 42));
263     * CHECK_COND(! (qnan <= 42));
264     * CHECK_COND(! (qnan >= 42));
265     */
266   }
267   return true;
268 }
269 
270 
271 class ArbitraryType
272 {};
273 
test()274 void LimitTest::test() {
275   CPPUNIT_CHECK(test_integral_limits_base(bool()));
276   CPPUNIT_CHECK(test_integral_limits(char()));
277   typedef signed char signed_char;
278   CPPUNIT_CHECK(test_signed_integral_limits(signed_char()));
279   typedef unsigned char unsigned_char;
280   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_char()));
281 #  if defined (_STLP_HAS_WCHAR_T) && !defined (_STLP_WCHAR_T_IS_USHORT)
282   CPPUNIT_CHECK(test_integral_limits(wchar_t()));
283 #  endif
284   CPPUNIT_CHECK(test_signed_integral_limits(short()));
285   typedef unsigned short unsigned_short;
286   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_short()));
287   CPPUNIT_CHECK(test_signed_integral_limits(int()));
288   typedef unsigned int unsigned_int;
289   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_int()));
290   CPPUNIT_CHECK(test_signed_integral_limits(long()));
291   typedef unsigned long unsigned_long;
292   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long()));
293 #  if defined (_STLP_LONG_LONG)
294   typedef _STLP_LONG_LONG long_long;
295   CPPUNIT_CHECK(test_signed_integral_limits(long_long()));
296   typedef unsigned _STLP_LONG_LONG unsigned_long_long;
297   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long_long()));
298 #endif
299 
300   CPPUNIT_CHECK(test_float_limits(float()));
301   CPPUNIT_CHECK(test_float_limits(double()));
302 #  if !defined ( _STLP_NO_LONG_DOUBLE )
303   typedef long double long_double;
304   CPPUNIT_CHECK(test_float_limits(long_double()));
305 #  endif
306 
307   CPPUNIT_ASSERT( !numeric_limits<ArbitraryType>::is_specialized );
308 }
309 
qnan_test()310 void LimitTest::qnan_test() {
311   CPPUNIT_CHECK(test_qnan(float()));
312   CPPUNIT_CHECK(test_qnan(double()));
313 #  if !defined ( _STLP_NO_LONG_DOUBLE )
314   typedef long double long_double;
315   CPPUNIT_CHECK(test_qnan(long_double()));
316 #  endif
317 }
318