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/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 | |