| 1 | // (c) Copyright Fernando Luis Cacciola Carballal 2000-2004 |
| 2 | // Use, modification, and distribution is subject to the Boost Software |
| 3 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| 4 | // http://www.boost.org/LICENSE_1_0.txt) |
| 5 | |
| 6 | // See library home page at http://www.boost.org/libs/numeric/conversion |
| 7 | // |
| 8 | // Contact the author at: fernando_cacciola@hotmail.com |
| 9 | // |
| 10 | #include<cstdlib> |
| 11 | #include<iostream> |
| 12 | #include<iomanip> |
| 13 | #include<string> |
| 14 | #include<typeinfo> |
| 15 | #include<vector> |
| 16 | #include<algorithm> |
| 17 | |
| 18 | #include "boost/config.hpp" |
| 19 | #include "boost/cstdint.hpp" |
| 20 | #include "boost/utility.hpp" |
| 21 | |
| 22 | // |
| 23 | // Borland 5.5 lacks the following math overloads |
| 24 | // |
| 25 | #if BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x551) |
| 26 | namespace std |
| 27 | { |
| 28 | |
| 29 | inline float ceil (float x) { return std::ceil ( static_cast<double>(x)); } |
| 30 | inline float floor (float x) { return std::floor ( static_cast<double>(x)); } |
| 31 | inline long double ceil (long double x) { return std::ceill (x); } |
| 32 | inline long double floor (long double x) { return std::floorl(x); } |
| 33 | |
| 34 | } // namespace std |
| 35 | #endif |
| 36 | |
| 37 | #include "boost/numeric/conversion/converter.hpp" |
| 38 | #include "boost/numeric/conversion/cast.hpp" |
| 39 | |
| 40 | #ifdef BOOST_BORLANDC |
| 41 | #pragma hdrstop |
| 42 | #endif |
| 43 | |
| 44 | #include "test_helpers.cpp" |
| 45 | #include "test_helpers2.cpp" |
| 46 | #include "test_helpers3.cpp" |
| 47 | |
| 48 | #include "boost/mpl/alias.hpp" |
| 49 | |
| 50 | using std::cout ; |
| 51 | |
| 52 | // A generic 'abs' function. |
| 53 | template<class N> inline N absG ( N v ) |
| 54 | { |
| 55 | return v < static_cast<N>(0) ? static_cast<N>(-v) : v ; |
| 56 | } |
| 57 | template<> inline unsigned char absG<unsigned char> ( unsigned char v ) { return v ; } |
| 58 | template<> inline unsigned short absG<unsigned short> ( unsigned short v ) { return v ; } |
| 59 | template<> inline unsigned int absG<unsigned int> ( unsigned int v ) { return v ; } |
| 60 | template<> inline unsigned long absG<unsigned long> ( unsigned long v ) { return v ; } |
| 61 | |
| 62 | template<class T> inline void unused_variable ( T const& ) {} |
| 63 | // |
| 64 | // The following function excersizes specific conversions that cover |
| 65 | // usual and boundary cases for each relevant combination. |
| 66 | // |
| 67 | void test_conversions() |
| 68 | { |
| 69 | using namespace boost ; |
| 70 | using namespace numeric ; |
| 71 | |
| 72 | // To help the test found possible bugs a random numbers are used. |
| 73 | #if !defined(BOOST_NO_STDC_NAMESPACE) |
| 74 | using std::rand ; |
| 75 | #endif |
| 76 | |
| 77 | boost::int16_t v16 ; |
| 78 | boost::uint16_t uv16 ; |
| 79 | boost::int32_t v32 ; |
| 80 | boost::uint32_t uv32 ; |
| 81 | |
| 82 | volatile float fv ; // avoid this to be cached internally in some fpu register |
| 83 | volatile double dv ; // avoid this to be cached internally in some fpu register |
| 84 | |
| 85 | // |
| 86 | // sample (representative) conversions: |
| 87 | // |
| 88 | cout << "Testing representative conversions\n" ; |
| 89 | |
| 90 | // integral to integral |
| 91 | |
| 92 | // signed to signed |
| 93 | |
| 94 | // not subranged |
| 95 | v16 = static_cast<boost::int16_t>(rand()); |
| 96 | TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::int16_t,v16,v16); |
| 97 | |
| 98 | // subranged |
| 99 | v16 = static_cast<boost::int16_t>(rand()); |
| 100 | TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::int32_t,v16,v16); |
| 101 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::highest() + boost::int32_t(1) ) ; |
| 102 | TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::lowest() - boost::int32_t(1) ) ; |
| 103 | |
| 104 | // signed to unsigned |
| 105 | |
| 106 | // subranged |
| 107 | v32 = absG(v: static_cast<boost::int32_t>(rand())); |
| 108 | v16 = absG(v: static_cast<boost::int16_t>(rand())); |
| 109 | TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::int32_t,v32,v32); |
| 110 | TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::int32_t,v16,v16); |
| 111 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::int32_t,bounds<boost::uint16_t>::highest() + boost::int32_t(1) ) ; |
| 112 | TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::uint32_t,boost::int32_t,boost::int32_t(-1) ) ; |
| 113 | |
| 114 | // unsigned to signed |
| 115 | |
| 116 | // not subranged |
| 117 | v32 = absG(v: static_cast<boost::int32_t>(rand())); |
| 118 | TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::uint32_t,v32,v32); |
| 119 | |
| 120 | // subranged |
| 121 | v16 = absG(v: static_cast<boost::int16_t>(rand())); |
| 122 | TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::uint32_t,v16,v16); |
| 123 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ; |
| 124 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ; |
| 125 | |
| 126 | // unsigned to unsigned |
| 127 | |
| 128 | // not subranged |
| 129 | uv16 = static_cast<boost::uint16_t>(rand()); |
| 130 | TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::uint16_t,uv16,uv16); |
| 131 | |
| 132 | // subranged |
| 133 | uv16 = static_cast<boost::uint16_t>(rand()); |
| 134 | TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,uv16,uv16); |
| 135 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ; |
| 136 | |
| 137 | // integral to float |
| 138 | |
| 139 | // from signed integral |
| 140 | v32 = static_cast<boost::int32_t>(rand()); |
| 141 | TEST_SUCCEEDING_CONVERSION_DEF(double,boost::int32_t,v32,v32); |
| 142 | |
| 143 | // from uint32_tegral |
| 144 | uv32 = static_cast<boost::uint32_t>(rand()); |
| 145 | TEST_SUCCEEDING_CONVERSION_DEF(double,boost::uint32_t,uv32,uv32); |
| 146 | |
| 147 | // float to integral |
| 148 | |
| 149 | // to signed integral |
| 150 | v32 = static_cast<boost::int32_t>(rand()); |
| 151 | TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,double,v32,v32); |
| 152 | |
| 153 | dv = static_cast<double>(bounds<boost::uint32_t>::highest()) + 1.0 ; |
| 154 | TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,dv) ; |
| 155 | TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,-dv) ; |
| 156 | |
| 157 | // float to float |
| 158 | |
| 159 | // not subranged |
| 160 | fv = static_cast<float>(rand()) / static_cast<float>(3) ; |
| 161 | TEST_SUCCEEDING_CONVERSION_DEF(double,float,fv,fv); |
| 162 | |
| 163 | |
| 164 | // subranged |
| 165 | fv = static_cast<float>(rand()) / static_cast<float>(3) ; |
| 166 | TEST_SUCCEEDING_CONVERSION_DEF(float,double,fv,fv); |
| 167 | TEST_POS_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::highest()) ; |
| 168 | TEST_NEG_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::lowest ()) ; |
| 169 | } |
| 170 | |
| 171 | // Custom OverflowHandler |
| 172 | struct custom_overflow_handler |
| 173 | { |
| 174 | void operator() ( boost::numeric::range_check_result r ) |
| 175 | { |
| 176 | if ( r == boost::numeric::cNegOverflow ) |
| 177 | cout << "negative_overflow detected!\n" ; |
| 178 | else if ( r == boost::numeric::cPosOverflow ) |
| 179 | cout << "positive_overflow detected!\n" ; |
| 180 | } |
| 181 | } ; |
| 182 | |
| 183 | template<class T, class S,class OverflowHandler> |
| 184 | void test_overflow_handler( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S), MATCH_FNTPL_ARG(OverflowHandler), |
| 185 | PostCondition pos, |
| 186 | PostCondition neg |
| 187 | ) |
| 188 | { |
| 189 | typedef boost::numeric::conversion_traits<T,S> traits ; |
| 190 | typedef boost::numeric::converter<T,S,traits,OverflowHandler> converter ; |
| 191 | |
| 192 | static const S psrc = boost::numeric::bounds<S>::highest(); |
| 193 | static const S nsrc = boost::numeric::bounds<S>::lowest (); |
| 194 | |
| 195 | static const T pres = static_cast<T>(psrc); |
| 196 | static const T nres = static_cast<T>(nsrc); |
| 197 | |
| 198 | test_conv_base ( ConversionInstance<converter>(pres,psrc,pos) ) ; |
| 199 | test_conv_base ( ConversionInstance<converter>(nres,nsrc,neg) ) ; |
| 200 | } |
| 201 | |
| 202 | template<class T, class S> |
| 203 | void test_overflow_handlers( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) ) |
| 204 | { |
| 205 | cout << "Testing Silent Overflow Handler policy\n" ; |
| 206 | |
| 207 | test_overflow_handler( SET_FNTPL_ARG(T), |
| 208 | SET_FNTPL_ARG(S), |
| 209 | SET_FNTPL_ARG(boost::numeric::silent_overflow_handler), |
| 210 | c_converted, |
| 211 | c_converted |
| 212 | ) ; |
| 213 | |
| 214 | cout << "Testing Default Overflow Handler policy\n" ; |
| 215 | |
| 216 | test_overflow_handler( SET_FNTPL_ARG(T), |
| 217 | SET_FNTPL_ARG(S), |
| 218 | SET_FNTPL_ARG(boost::numeric::def_overflow_handler), |
| 219 | c_pos_overflow, |
| 220 | c_neg_overflow |
| 221 | ) ; |
| 222 | |
| 223 | cout << "Testing Custom (User-Defined) Overflow Handler policy\n" ; |
| 224 | |
| 225 | test_overflow_handler( SET_FNTPL_ARG(T), |
| 226 | SET_FNTPL_ARG(S), |
| 227 | SET_FNTPL_ARG(custom_overflow_handler), |
| 228 | c_converted, |
| 229 | c_converted |
| 230 | ) ; |
| 231 | } |
| 232 | |
| 233 | // For a given float-type number 'n' of integer value (n.0), check the conversions |
| 234 | // within the range [n-1,n+1] taking values at: (n-1,n-0.5,n,n+0.5,n+1). |
| 235 | // For each sampled value there is an expected result and a PostCondition according to the |
| 236 | // specified round_style. |
| 237 | // |
| 238 | template<class T, class S, class Float2IntRounder> |
| 239 | void test_rounding_conversion ( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(Float2IntRounder), |
| 240 | S s, |
| 241 | PostCondition resl1, |
| 242 | PostCondition resl0, |
| 243 | PostCondition res, |
| 244 | PostCondition resr0, |
| 245 | PostCondition resr1 |
| 246 | ) |
| 247 | { |
| 248 | typedef boost::numeric::conversion_traits<T,S> Traits ; |
| 249 | |
| 250 | typedef boost::numeric::converter<T,S, Traits, boost::numeric::def_overflow_handler,Float2IntRounder> |
| 251 | Converter ; |
| 252 | |
| 253 | S sl1 = s - static_cast<S>(1); |
| 254 | S sl0 = s - static_cast<S>(0.5); |
| 255 | S sr0 = s + static_cast<S>(0.5); |
| 256 | S sr1 = s + static_cast<S>(1); |
| 257 | |
| 258 | T tl1 = static_cast<T>( Converter::nearbyint(sl1) ); |
| 259 | T tl0 = static_cast<T>( Converter::nearbyint(sl0) ); |
| 260 | T t = static_cast<T>( Converter::nearbyint(s) ); |
| 261 | T tr0 = static_cast<T>( Converter::nearbyint(sr0) ); |
| 262 | T tr1 = static_cast<T>( Converter::nearbyint(sr1) ); |
| 263 | |
| 264 | test_conv_base ( ConversionInstance<Converter>(tl1,sl1,resl1) ) ; |
| 265 | test_conv_base ( ConversionInstance<Converter>(tl0,sl0,resl0) ) ; |
| 266 | test_conv_base ( ConversionInstance<Converter>(t,s,res) ) ; |
| 267 | test_conv_base ( ConversionInstance<Converter>(tr0,sr0,resr0) ) ; |
| 268 | test_conv_base ( ConversionInstance<Converter>(tr1,sr1,resr1) ) ; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | template<class T,class S> |
| 273 | void test_round_style( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) ) |
| 274 | { |
| 275 | S min = boost::numeric::bounds<T>::lowest(); |
| 276 | S max = boost::numeric::bounds<T>::highest(); |
| 277 | |
| 278 | cout << "Testing 'Trunc' Float2IntRounder policy\n" ; |
| 279 | |
| 280 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 281 | SET_FNTPL_ARG(boost::numeric::Trunc<S>), |
| 282 | min, |
| 283 | c_neg_overflow, |
| 284 | c_converted, |
| 285 | c_converted, |
| 286 | c_converted, |
| 287 | c_converted |
| 288 | ) ; |
| 289 | |
| 290 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 291 | SET_FNTPL_ARG(boost::numeric::Trunc<S>), |
| 292 | max, |
| 293 | c_converted, |
| 294 | c_converted, |
| 295 | c_converted, |
| 296 | c_converted, |
| 297 | c_pos_overflow |
| 298 | ) ; |
| 299 | |
| 300 | cout << "Testing 'RoundEven' Float2IntRounder policy\n" ; |
| 301 | |
| 302 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 303 | SET_FNTPL_ARG(boost::numeric::RoundEven<S>), |
| 304 | min, |
| 305 | c_neg_overflow, |
| 306 | c_converted, |
| 307 | c_converted, |
| 308 | c_converted, |
| 309 | c_converted |
| 310 | ) ; |
| 311 | |
| 312 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 313 | SET_FNTPL_ARG(boost::numeric::RoundEven<S>), |
| 314 | max, |
| 315 | c_converted, |
| 316 | c_converted, |
| 317 | c_converted, |
| 318 | c_pos_overflow, |
| 319 | c_pos_overflow |
| 320 | ) ; |
| 321 | |
| 322 | cout << "Testing 'Ceil' Float2IntRounder policy\n" ; |
| 323 | |
| 324 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 325 | SET_FNTPL_ARG(boost::numeric::Ceil<S>), |
| 326 | min, |
| 327 | c_neg_overflow, |
| 328 | c_converted, |
| 329 | c_converted, |
| 330 | c_converted, |
| 331 | c_converted |
| 332 | ) ; |
| 333 | |
| 334 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 335 | SET_FNTPL_ARG(boost::numeric::Ceil<S>), |
| 336 | max, |
| 337 | c_converted, |
| 338 | c_converted, |
| 339 | c_converted, |
| 340 | c_pos_overflow, |
| 341 | c_pos_overflow |
| 342 | ) ; |
| 343 | |
| 344 | cout << "Testing 'Floor' Float2IntRounder policy\n" ; |
| 345 | |
| 346 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 347 | SET_FNTPL_ARG(boost::numeric::Floor<S>), |
| 348 | min, |
| 349 | c_neg_overflow, |
| 350 | c_neg_overflow, |
| 351 | c_converted, |
| 352 | c_converted, |
| 353 | c_converted |
| 354 | ) ; |
| 355 | |
| 356 | test_rounding_conversion(SET_FNTPL_ARG(T), |
| 357 | SET_FNTPL_ARG(boost::numeric::Floor<S>), |
| 358 | max, |
| 359 | c_converted, |
| 360 | c_converted, |
| 361 | c_converted, |
| 362 | c_converted, |
| 363 | c_pos_overflow |
| 364 | ) ; |
| 365 | |
| 366 | } |
| 367 | |
| 368 | void test_round_even( double n, double x ) |
| 369 | { |
| 370 | double r = boost::numeric::RoundEven<double>::nearbyint(s: n); |
| 371 | BOOST_TEST( r == x ) ; |
| 372 | } |
| 373 | |
| 374 | void test_round_even() |
| 375 | { |
| 376 | cout << "Testing 'RoundEven' tie-breaking\n" ; |
| 377 | |
| 378 | double min = boost::numeric::bounds<double>::lowest(); |
| 379 | double max = boost::numeric::bounds<double>::highest(); |
| 380 | |
| 381 | #if !defined(BOOST_NO_STDC_NAMESPACE) |
| 382 | using std::floor ; |
| 383 | using std::ceil ; |
| 384 | #endif |
| 385 | test_round_even(n: min, x: floor(x: min)); |
| 386 | test_round_even(n: max, x: ceil (x: max)); |
| 387 | test_round_even(n: 2.0, x: 2.0); |
| 388 | test_round_even(n: 2.3, x: 2.0); |
| 389 | test_round_even(n: 2.5, x: 2.0); |
| 390 | test_round_even(n: 2.7, x: 3.0); |
| 391 | test_round_even(n: 3.0, x: 3.0); |
| 392 | test_round_even(n: 3.3, x: 3.0); |
| 393 | test_round_even(n: 3.5, x: 4.0); |
| 394 | test_round_even(n: 3.7, x: 4.0); |
| 395 | } |
| 396 | |
| 397 | int double_to_int ( double n ) { return static_cast<int>(n) ; } |
| 398 | |
| 399 | void test_converter_as_function_object() |
| 400 | { |
| 401 | cout << "Testing converter as function object.\n" ; |
| 402 | |
| 403 | // Create a sample sequence of double values. |
| 404 | std::vector<double> S ; |
| 405 | for ( int i = 0 ; i < 10 ; ++ i ) |
| 406 | S.push_back( x: i * ( 18.0 / 19.0 ) ); |
| 407 | |
| 408 | // Create a sequence of int values from 's' using the standard conversion. |
| 409 | std::vector<int> W ; |
| 410 | std::transform(first: S.begin(),last: S.end(),result: std::back_inserter(x&: W),unary_op: double_to_int); |
| 411 | |
| 412 | // Create a sequence of int values from s using a default numeric::converter |
| 413 | std::vector<int> I ; |
| 414 | std::transform(first: S.begin(), |
| 415 | last: S.end(), |
| 416 | result: std::back_inserter(x&: I), |
| 417 | unary_op: boost::numeric::converter<int,double>() |
| 418 | ) ; |
| 419 | |
| 420 | // Match 'w' and 'i' which should be equal. |
| 421 | bool double_to_int_OK = std::equal(first1: W.begin(),last1: W.end(),first2: I.begin()) ; |
| 422 | BOOST_TEST(double_to_int_OK); |
| 423 | |
| 424 | // Create a sequence of double values from s using a default numeric::converter (which should be the trivial conv). |
| 425 | std::vector<double> D ; |
| 426 | std::transform(first: S.begin(), |
| 427 | last: S.end(), |
| 428 | result: std::back_inserter(x&: D), |
| 429 | unary_op: boost::numeric::converter<double,double>() |
| 430 | ) ; |
| 431 | |
| 432 | // Match 's' and 'd' which should be equal. |
| 433 | bool double_to_double_OK = std::equal(first1: S.begin(),last1: S.end(),first2: D.begin()) ; |
| 434 | BOOST_TEST(double_to_double_OK); |
| 435 | } |
| 436 | |
| 437 | #if BOOST_WORKAROUND(__IBMCPP__, <= 600 ) // VCAPP6 |
| 438 | # define UNOPTIMIZED |
| 439 | #else |
| 440 | # define UNOPTIMIZED volatile |
| 441 | #endif |
| 442 | |
| 443 | void test_optimizations() |
| 444 | { |
| 445 | using namespace boost; |
| 446 | using namespace numeric; |
| 447 | |
| 448 | float fv0 = 18.0f / 19.0f ; |
| 449 | |
| 450 | // This code deosn't produce any output. |
| 451 | // It is intended to show the optimization of numeric::converter<> by manual inspection |
| 452 | // of the generated code. |
| 453 | // Each test shows first the equivalent hand-coded version. |
| 454 | // The numeric_cast<> code should be the same if full compiler optimization/inlining is used. |
| 455 | |
| 456 | //--------------------------------- |
| 457 | // trivial conversion. |
| 458 | // |
| 459 | // equivalent code: |
| 460 | UNOPTIMIZED float fv1a = fv0 ; |
| 461 | |
| 462 | float fv1b = numeric_cast<float>(arg: fv0); |
| 463 | unused_variable(fv1a); |
| 464 | unused_variable(fv1b); |
| 465 | // |
| 466 | //--------------------------------- |
| 467 | |
| 468 | //--------------------------------- |
| 469 | // nonsubranged conversion. |
| 470 | // |
| 471 | // equivalent code: |
| 472 | UNOPTIMIZED double dv1a = static_cast<double>(fv0); |
| 473 | |
| 474 | double dv1b = numeric_cast<double>(arg: fv0); |
| 475 | unused_variable(dv1a); |
| 476 | unused_variable(dv1b); |
| 477 | // |
| 478 | //--------------------------------- |
| 479 | |
| 480 | //------------------------------------------------------ |
| 481 | // subranged conversion with both-sided range checking. |
| 482 | // |
| 483 | |
| 484 | // equivalent code: |
| 485 | |
| 486 | { |
| 487 | double const& s = dv1b ; |
| 488 | // range checking |
| 489 | range_check_result r = s < static_cast<double>(bounds<float>::lowest()) |
| 490 | ? cNegOverflow : cInRange ; |
| 491 | if ( r == cInRange ) |
| 492 | { |
| 493 | r = s > static_cast<double>(bounds<float>::highest()) ? cPosOverflow : cInRange ; |
| 494 | } |
| 495 | if ( r == cNegOverflow ) |
| 496 | throw negative_overflow() ; |
| 497 | else if ( r == cPosOverflow ) |
| 498 | throw positive_overflow() ; |
| 499 | // conversion |
| 500 | UNOPTIMIZED float fv2a = static_cast<float>(s); |
| 501 | unused_variable(fv2a); |
| 502 | } |
| 503 | |
| 504 | float fv2b = numeric_cast<float>(arg: dv1b); |
| 505 | unused_variable(fv2b); |
| 506 | // |
| 507 | //--------------------------------- |
| 508 | |
| 509 | |
| 510 | //--------------------------------- |
| 511 | // subranged rounding conversion |
| 512 | // |
| 513 | // equivalent code: |
| 514 | |
| 515 | { |
| 516 | double const& s = dv1b ; |
| 517 | // range checking |
| 518 | range_check_result r = s <= static_cast<double>(bounds<int>::lowest()) - static_cast<double>(1.0) |
| 519 | ? cNegOverflow : cInRange ; |
| 520 | if ( r == cInRange ) |
| 521 | { |
| 522 | r = s >= static_cast<double>(bounds<int>::highest()) + static_cast<double>(1.0) |
| 523 | ? cPosOverflow : cInRange ; |
| 524 | } |
| 525 | if ( r == cNegOverflow ) |
| 526 | throw negative_overflow() ; |
| 527 | else if ( r == cPosOverflow ) |
| 528 | throw positive_overflow() ; |
| 529 | // rounding |
| 530 | |
| 531 | #if !defined(BOOST_NO_STDC_NAMESPACE) |
| 532 | using std::floor ; |
| 533 | #endif |
| 534 | |
| 535 | double s1 = floor(x: dv1b + 0.5); |
| 536 | |
| 537 | // conversion |
| 538 | UNOPTIMIZED int iv1a = static_cast<int>(s1); |
| 539 | unused_variable(iv1a); |
| 540 | } |
| 541 | |
| 542 | int iv1b = numeric_cast<int>(arg: dv1b); |
| 543 | unused_variable(iv1b); |
| 544 | // |
| 545 | //--------------------------------- |
| 546 | } |
| 547 | |
| 548 | int main() |
| 549 | { |
| 550 | std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ; |
| 551 | |
| 552 | test_conversions(); |
| 553 | test_overflow_handlers( SET_FNTPL_ARG(boost::int16_t), SET_FNTPL_ARG(boost::int32_t)); |
| 554 | test_round_style(SET_FNTPL_ARG(boost::int32_t), SET_FNTPL_ARG(double) ) ; |
| 555 | test_round_even() ; |
| 556 | test_converter_as_function_object(); |
| 557 | test_optimizations() ; |
| 558 | |
| 559 | return boost::report_errors(); |
| 560 | } |
| 561 | //--------------------------------------------------------------------------- |
| 562 | |
| 563 | |