Home | History | Annotate | Download | only in conversion
      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 (at) hotmail.com
      9 //
     10 #ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
     11 #define BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
     12 
     13 #include <typeinfo> // for std::bad_cast
     14 
     15 #include <boost/config/no_tr1/cmath.hpp> // for std::floor and std::ceil
     16 #include <boost/throw_exception.hpp>
     17 
     18 #include <functional>
     19 
     20 #include "boost/type_traits/is_arithmetic.hpp"
     21 
     22 #include "boost/mpl/if.hpp"
     23 #include "boost/mpl/integral_c.hpp"
     24 
     25 namespace boost { namespace numeric
     26 {
     27 
     28 template<class S>
     29 struct Trunc
     30 {
     31   typedef S source_type ;
     32 
     33   typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
     34 
     35   static source_type nearbyint ( argument_type s )
     36   {
     37 #if !defined(BOOST_NO_STDC_NAMESPACE)
     38     using std::floor ;
     39     using std::ceil  ;
     40 #endif
     41 
     42     return s < static_cast<S>(0) ? ceil(s) : floor(s) ;
     43   }
     44 
     45   typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ;
     46 } ;
     47 
     48 
     49 
     50 template<class S>
     51 struct Floor
     52 {
     53   typedef S source_type ;
     54 
     55   typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
     56 
     57   static source_type nearbyint ( argument_type s )
     58   {
     59 #if !defined(BOOST_NO_STDC_NAMESPACE)
     60     using std::floor ;
     61 #endif
     62 
     63     return floor(s) ;
     64   }
     65 
     66   typedef mpl::integral_c< std::float_round_style, std::round_toward_neg_infinity> round_style ;
     67 } ;
     68 
     69 template<class S>
     70 struct Ceil
     71 {
     72   typedef S source_type ;
     73 
     74   typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
     75 
     76   static source_type nearbyint ( argument_type s )
     77   {
     78 #if !defined(BOOST_NO_STDC_NAMESPACE)
     79     using std::ceil ;
     80 #endif
     81 
     82     return ceil(s) ;
     83   }
     84 
     85   typedef mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style ;
     86 } ;
     87 
     88 template<class S>
     89 struct RoundEven
     90 {
     91   typedef S source_type ;
     92 
     93   typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
     94 
     95   static source_type nearbyint ( argument_type s )
     96   {
     97     // Algorithm contributed by Guillaume Melquiond
     98 
     99 #if !defined(BOOST_NO_STDC_NAMESPACE)
    100     using std::floor ;
    101     using std::ceil  ;
    102 #endif
    103 
    104     // only works inside the range not at the boundaries
    105     S prev = floor(s);
    106     S next = ceil(s);
    107 
    108     S rt = (s - prev) - (next - s); // remainder type
    109 
    110     S const zero(0.0);
    111     S const two(2.0);
    112 
    113     if ( rt < zero )
    114       return prev;
    115     else if ( rt > zero )
    116       return next;
    117     else
    118     {
    119       bool is_prev_even = two * floor(prev / two) == prev ;
    120       return ( is_prev_even ? prev : next ) ;
    121     }
    122   }
    123 
    124   typedef mpl::integral_c< std::float_round_style, std::round_to_nearest> round_style ;
    125 } ;
    126 
    127 
    128 enum range_check_result
    129 {
    130   cInRange     = 0 ,
    131   cNegOverflow = 1 ,
    132   cPosOverflow = 2
    133 } ;
    134 
    135 class bad_numeric_cast : public std::bad_cast
    136 {
    137   public:
    138 
    139     virtual const char * what() const throw()
    140       {  return "bad numeric conversion: overflow"; }
    141 };
    142 
    143 class negative_overflow : public bad_numeric_cast
    144 {
    145   public:
    146 
    147     virtual const char * what() const throw()
    148       {  return "bad numeric conversion: negative overflow"; }
    149 };
    150 class positive_overflow : public bad_numeric_cast
    151 {
    152   public:
    153 
    154     virtual const char * what() const throw()
    155       { return "bad numeric conversion: positive overflow"; }
    156 };
    157 
    158 struct def_overflow_handler
    159 {
    160   void operator() ( range_check_result r ) // throw(negative_overflow,positive_overflow)
    161   {
    162 #ifndef BOOST_NO_EXCEPTIONS
    163     if ( r == cNegOverflow )
    164       throw negative_overflow() ;
    165     else if ( r == cPosOverflow )
    166            throw positive_overflow() ;
    167 #else
    168     if ( r == cNegOverflow )
    169       ::boost::throw_exception(negative_overflow()) ;
    170     else if ( r == cPosOverflow )
    171            ::boost::throw_exception(positive_overflow()) ;
    172 #endif
    173   }
    174 } ;
    175 
    176 struct silent_overflow_handler
    177 {
    178   void operator() ( range_check_result ) {} // throw()
    179 } ;
    180 
    181 template<class Traits>
    182 struct raw_converter
    183 {
    184   typedef typename Traits::result_type   result_type   ;
    185   typedef typename Traits::argument_type argument_type ;
    186 
    187   static result_type low_level_convert ( argument_type s ) { return static_cast<result_type>(s) ; }
    188 } ;
    189 
    190 struct UseInternalRangeChecker {} ;
    191 
    192 } } // namespace boost::numeric
    193 
    194 #endif
    195