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