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. 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 60 bool valid_sign_info(bool, bool) 61 { return true; } 62 63 template <class _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> 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> 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> 111 bool test_signed_integral_limits(const _Tp &__val) { 112 return test_integral_limits(__val, false, true); 113 } 114 template <class _Tp> 115 bool test_unsigned_integral_limits(const _Tp &__val) { 116 return test_integral_limits(__val, false, false); 117 } 118 119 template <class _Tp> 120 bool test_float_values(_Tp lhs, _Tp rhs) 121 { return lhs == rhs; } 122 123 template <class _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> 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 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)) && WCHAR_MIN != 0 && !defined(__arm__) 282 /* wchar_t is unsigned in arm */ 283 CPPUNIT_CHECK(test_integral_limits(wchar_t())); 284 # endif 285 CPPUNIT_CHECK(test_signed_integral_limits(short())); 286 typedef unsigned short unsigned_short; 287 CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_short())); 288 CPPUNIT_CHECK(test_signed_integral_limits(int())); 289 typedef unsigned int unsigned_int; 290 CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_int())); 291 CPPUNIT_CHECK(test_signed_integral_limits(long())); 292 typedef unsigned long unsigned_long; 293 CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long())); 294 # if defined (_STLP_LONG_LONG) 295 typedef _STLP_LONG_LONG long_long; 296 CPPUNIT_CHECK(test_signed_integral_limits(long_long())); 297 typedef unsigned _STLP_LONG_LONG unsigned_long_long; 298 CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long_long())); 299 #endif 300 301 CPPUNIT_CHECK(test_float_limits(float())); 302 CPPUNIT_CHECK(test_float_limits(double())); 303 # if !defined ( _STLP_NO_LONG_DOUBLE ) 304 typedef long double long_double; 305 CPPUNIT_CHECK(test_float_limits(long_double())); 306 # endif 307 308 CPPUNIT_ASSERT( !numeric_limits<ArbitraryType>::is_specialized ); 309 } 310 311 void LimitTest::qnan_test() { 312 CPPUNIT_CHECK(test_qnan(float())); 313 CPPUNIT_CHECK(test_qnan(double())); 314 # if !defined ( _STLP_NO_LONG_DOUBLE ) 315 typedef long double long_double; 316 CPPUNIT_CHECK(test_qnan(long_double())); 317 # endif 318 } 319