]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/numeric/conversion/test/converter_test.cpp
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)
6 // See library home page at http://www.boost.org/libs/numeric/conversion
8 // Contact the author at: fernando_cacciola@hotmail.com
18 #include "boost/config.hpp"
19 #include "boost/cstdint.hpp"
20 #include "boost/utility.hpp"
23 // Borland 5.5 lacks the following math overloads
25 #if BOOST_WORKAROUND(__BORLANDC__, <= 0x551)
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
); }
37 #include "boost/numeric/conversion/converter.hpp"
38 #include "boost/numeric/conversion/cast.hpp"
44 #include "test_helpers.cpp"
45 #include "test_helpers2.cpp"
46 #include "test_helpers3.cpp"
48 #include "boost/mpl/alias.hpp"
52 // A generic 'abs' function.
53 template<class N
> inline N
absG ( N v
)
55 return v
< static_cast<N
>(0) ? static_cast<N
>(-v
) : v
;
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
; }
62 template<class T
> inline void unused_variable ( T
const& ) {}
64 // The following function excersizes specific conversions that cover
65 // usual and boundary cases for each relevant combination.
67 void test_conversions()
69 using namespace boost
;
70 using namespace numeric
;
72 // To help the test found possible bugs a random numbers are used.
73 #if !defined(BOOST_NO_STDC_NAMESPACE)
78 boost::uint16_t uv16
;
80 boost::uint32_t uv32
;
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
86 // sample (representative) conversions:
88 cout
<< "Testing representative conversions\n";
90 // integral to integral
95 v16
= static_cast<boost::int16_t>(rand());
96 TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::int16_t,v16
,v16
);
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) ) ;
104 // signed to unsigned
107 v32
= absG(static_cast<boost::int32_t>(rand()));
108 v16
= absG(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) ) ;
114 // unsigned to signed
117 v32
= absG(static_cast<boost::int32_t>(rand()));
118 TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::uint32_t,v32
,v32
);
121 v16
= absG(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() ) ;
126 // unsigned to unsigned
129 uv16
= static_cast<boost::uint16_t>(rand());
130 TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::uint16_t,uv16
,uv16
);
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() ) ;
139 // from signed integral
140 v32
= static_cast<boost::int32_t>(rand());
141 TEST_SUCCEEDING_CONVERSION_DEF(double,boost::int32_t,v32
,v32
);
143 // from uint32_tegral
144 uv32
= static_cast<boost::uint32_t>(rand());
145 TEST_SUCCEEDING_CONVERSION_DEF(double,boost::uint32_t,uv32
,uv32
);
149 // to signed integral
150 v32
= static_cast<boost::int32_t>(rand());
151 TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,double,v32
,v32
);
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
) ;
160 fv
= static_cast<float>(rand()) / static_cast<float>(3) ;
161 TEST_SUCCEEDING_CONVERSION_DEF(double,float,fv
,fv
);
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 ()) ;
171 // Custom OverflowHandler
172 struct custom_overflow_handler
174 void operator() ( boost::numeric::range_check_result r
)
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" ;
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
),
189 typedef boost::numeric::conversion_traits
<T
,S
> traits
;
190 typedef boost::numeric::converter
<T
,S
,traits
,OverflowHandler
> converter
;
192 static const S psrc
= boost::numeric::bounds
<S
>::highest();
193 static const S nsrc
= boost::numeric::bounds
<S
>::lowest ();
195 static const T pres
= static_cast<T
>(psrc
);
196 static const T nres
= static_cast<T
>(nsrc
);
198 test_conv_base ( ConversionInstance
<converter
>(pres
,psrc
,pos
) ) ;
199 test_conv_base ( ConversionInstance
<converter
>(nres
,nsrc
,neg
) ) ;
202 template<class T
, class S
>
203 void test_overflow_handlers( MATCH_FNTPL_ARG(T
), MATCH_FNTPL_ARG(S
) )
205 cout
<< "Testing Silent Overflow Handler policy\n";
207 test_overflow_handler( SET_FNTPL_ARG(T
),
209 SET_FNTPL_ARG(boost::numeric::silent_overflow_handler
),
214 cout
<< "Testing Default Overflow Handler policy\n";
216 test_overflow_handler( SET_FNTPL_ARG(T
),
218 SET_FNTPL_ARG(boost::numeric::def_overflow_handler
),
223 cout
<< "Testing Custom (User-Defined) Overflow Handler policy\n";
225 test_overflow_handler( SET_FNTPL_ARG(T
),
227 SET_FNTPL_ARG(custom_overflow_handler
),
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.
238 template<class T
, class S
, class Float2IntRounder
>
239 void test_rounding_conversion ( MATCH_FNTPL_ARG(T
), MATCH_FNTPL_ARG(Float2IntRounder
),
248 typedef boost::numeric::conversion_traits
<T
,S
> Traits
;
250 typedef boost::numeric::converter
<T
,S
, Traits
, boost::numeric::def_overflow_handler
,Float2IntRounder
>
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);
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
) );
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
) ) ;
272 template<class T
,class S
>
273 void test_round_style( MATCH_FNTPL_ARG(T
), MATCH_FNTPL_ARG(S
) )
275 S min
= boost::numeric::bounds
<T
>::lowest();
276 S max
= boost::numeric::bounds
<T
>::highest();
278 cout
<< "Testing 'Trunc' Float2IntRounder policy\n";
280 test_rounding_conversion(SET_FNTPL_ARG(T
),
281 SET_FNTPL_ARG(boost::numeric::Trunc
<S
>),
290 test_rounding_conversion(SET_FNTPL_ARG(T
),
291 SET_FNTPL_ARG(boost::numeric::Trunc
<S
>),
300 cout
<< "Testing 'RoundEven' Float2IntRounder policy\n";
302 test_rounding_conversion(SET_FNTPL_ARG(T
),
303 SET_FNTPL_ARG(boost::numeric::RoundEven
<S
>),
312 test_rounding_conversion(SET_FNTPL_ARG(T
),
313 SET_FNTPL_ARG(boost::numeric::RoundEven
<S
>),
322 cout
<< "Testing 'Ceil' Float2IntRounder policy\n";
324 test_rounding_conversion(SET_FNTPL_ARG(T
),
325 SET_FNTPL_ARG(boost::numeric::Ceil
<S
>),
334 test_rounding_conversion(SET_FNTPL_ARG(T
),
335 SET_FNTPL_ARG(boost::numeric::Ceil
<S
>),
344 cout
<< "Testing 'Floor' Float2IntRounder policy\n" ;
346 test_rounding_conversion(SET_FNTPL_ARG(T
),
347 SET_FNTPL_ARG(boost::numeric::Floor
<S
>),
356 test_rounding_conversion(SET_FNTPL_ARG(T
),
357 SET_FNTPL_ARG(boost::numeric::Floor
<S
>),
368 void test_round_even( double n
, double x
)
370 double r
= boost::numeric::RoundEven
<double>::nearbyint(n
);
371 BOOST_CHECK( r
== x
) ;
374 void test_round_even()
376 cout
<< "Testing 'RoundEven' tie-breaking\n";
378 double min
= boost::numeric::bounds
<double>::lowest();
379 double max
= boost::numeric::bounds
<double>::highest();
381 #if !defined(BOOST_NO_STDC_NAMESPACE)
385 test_round_even(min
, floor(min
));
386 test_round_even(max
, ceil (max
));
387 test_round_even(2.0, 2.0);
388 test_round_even(2.3, 2.0);
389 test_round_even(2.5, 2.0);
390 test_round_even(2.7, 3.0);
391 test_round_even(3.0, 3.0);
392 test_round_even(3.3, 3.0);
393 test_round_even(3.5, 4.0);
394 test_round_even(3.7, 4.0);
397 int double_to_int ( double n
) { return static_cast<int>(n
) ; }
399 void test_converter_as_function_object()
401 cout
<< "Testing converter as function object.\n";
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( i
* ( 18.0 / 19.0 ) );
408 // Create a sequence of int values from 's' using the standard conversion.
410 std::transform(S
.begin(),S
.end(),std::back_inserter(W
),double_to_int
);
412 // Create a sequence of int values from s using a default numeric::converter
414 std::transform(S
.begin(),
416 std::back_inserter(I
),
417 boost::numeric::converter
<int,double>()
420 // Match 'w' and 'i' which should be equal.
421 bool double_to_int_OK
= std::equal(W
.begin(),W
.end(),I
.begin()) ;
422 BOOST_CHECK_MESSAGE(double_to_int_OK
, "converter (int,double) as function object");
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(S
.begin(),
428 std::back_inserter(D
),
429 boost::numeric::converter
<double,double>()
432 // Match 's' and 'd' which should be equal.
433 bool double_to_double_OK
= std::equal(S
.begin(),S
.end(),D
.begin()) ;
434 BOOST_CHECK_MESSAGE(double_to_double_OK
, "converter (double,double) as function object");
437 #if BOOST_WORKAROUND(__IBMCPP__, <= 600 ) // VCAPP6
440 # define UNOPTIMIZED volatile
443 void test_optimizations()
445 using namespace boost
;
446 using namespace numeric
;
448 float fv0
= 18.0f
/ 19.0f
;
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.
456 //---------------------------------
457 // trivial conversion.
460 UNOPTIMIZED
float fv1a
= fv0
;
462 float fv1b
= numeric_cast
<float>(fv0
);
463 unused_variable(fv1a
);
464 unused_variable(fv1b
);
466 //---------------------------------
468 //---------------------------------
469 // nonsubranged conversion.
472 UNOPTIMIZED
double dv1a
= static_cast<double>(fv0
);
474 double dv1b
= numeric_cast
<double>(fv0
);
475 unused_variable(dv1a
);
476 unused_variable(dv1b
);
478 //---------------------------------
480 //------------------------------------------------------
481 // subranged conversion with both-sided range checking.
487 double const& s
= dv1b
;
489 range_check_result r
= s
< static_cast<double>(bounds
<float>::lowest())
490 ? cNegOverflow
: cInRange
;
493 r
= s
> static_cast<double>(bounds
<float>::highest()) ? cPosOverflow
: cInRange
;
495 if ( r
== cNegOverflow
)
496 throw negative_overflow() ;
497 else if ( r
== cPosOverflow
)
498 throw positive_overflow() ;
500 UNOPTIMIZED
float fv2a
= static_cast<float>(s
);
501 unused_variable(fv2a
);
504 float fv2b
= numeric_cast
<float>(dv1b
);
505 unused_variable(fv2b
);
507 //---------------------------------
510 //---------------------------------
511 // subranged rounding conversion
516 double const& s
= dv1b
;
518 range_check_result r
= s
<= static_cast<double>(bounds
<int>::lowest()) - static_cast<double>(1.0)
519 ? cNegOverflow
: cInRange
;
522 r
= s
>= static_cast<double>(bounds
<int>::highest()) + static_cast<double>(1.0)
523 ? cPosOverflow
: cInRange
;
525 if ( r
== cNegOverflow
)
526 throw negative_overflow() ;
527 else if ( r
== cPosOverflow
)
528 throw positive_overflow() ;
531 #if !defined(BOOST_NO_STDC_NAMESPACE)
535 double s1
= floor(dv1b
+ 0.5);
538 UNOPTIMIZED
int iv1a
= static_cast<int>(s1
);
539 unused_variable(iv1a
);
542 int iv1b
= numeric_cast
<int>(dv1b
);
543 unused_variable(iv1b
);
545 //---------------------------------
548 int test_main( int, char* argv
[] )
550 std::cout
<< std::setprecision( std::numeric_limits
<long double>::digits10
) ;
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) ) ;
556 test_converter_as_function_object();
557 test_optimizations() ;
561 //---------------------------------------------------------------------------