limits_test.cpp revision e46c9386c4f79aa40185f79a19fc5b2a7ef528b3
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)
21using namespace std;
22#endif
23
24//
25// TestCase class
26//
27class 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
44protected:
45  void test();
46  void qnan_test();
47};
48
49CPPUNIT_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.
56bool check_cond(const bool& cond) { return cond; }
57#  define CHECK_COND(X) if (!check_cond(X)) { CPPUNIT_MESSAGE(#X); return false; }
58#endif
59
60bool valid_sign_info(bool, bool)
61{ return true; }
62
63template <class _Tp>
64bool 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
69template <class _Tp>
70bool 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
87template <class _Tp>
88bool 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
110template <class _Tp>
111bool test_signed_integral_limits(const _Tp &__val) {
112  return test_integral_limits(__val, false, true);
113}
114template <class _Tp>
115bool test_unsigned_integral_limits(const _Tp &__val) {
116  return test_integral_limits(__val, false, false);
117}
118
119template <class _Tp>
120bool test_float_values(_Tp lhs, _Tp rhs)
121{ return lhs == rhs; }
122
123template <class _Tp>
124bool 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//}
232template <class _Tp>
233bool 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
271class ArbitraryType
272{};
273
274void 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
310void 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