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 | |
36 | 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 | |
58 | 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 | |
77 | 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 | |
96 | 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 | |
140 | 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 | |
148 | 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 | |
155 | virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW |
156 | { return "bad numeric conversion: positive overflow" ; } |
157 | }; |
158 | |
159 | struct def_overflow_handler |
160 | { |
161 | 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 | { |
179 | 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 | |
188 | 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 | |