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