Chris@16
|
1 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 // Copyright 2011 John Maddock. Distributed under the Boost
|
Chris@16
|
3 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP
|
Chris@16
|
7 #define BOOST_MP_GENERIC_INTERCONVERT_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/multiprecision/detail/default_ops.hpp>
|
Chris@16
|
10
|
Chris@16
|
11 namespace boost{ namespace multiprecision{ namespace detail{
|
Chris@16
|
12
|
Chris@16
|
13 template <class To, class From>
|
Chris@16
|
14 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
Chris@16
|
15 {
|
Chris@16
|
16 using default_ops::eval_get_sign;
|
Chris@16
|
17 using default_ops::eval_bitwise_and;
|
Chris@16
|
18 using default_ops::eval_convert_to;
|
Chris@16
|
19 using default_ops::eval_right_shift;
|
Chris@16
|
20 using default_ops::eval_ldexp;
|
Chris@16
|
21 using default_ops::eval_add;
|
Chris@16
|
22 // smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
Chris@16
|
23 typedef typename canonical<unsigned char, From>::type limb_type;
|
Chris@16
|
24 // get the corresponding type that we can assign to "To":
|
Chris@16
|
25 typedef typename canonical<limb_type, To>::type to_type;
|
Chris@16
|
26 From t(from);
|
Chris@16
|
27 bool is_neg = eval_get_sign(t) < 0;
|
Chris@16
|
28 if(is_neg)
|
Chris@16
|
29 t.negate();
|
Chris@16
|
30 // Pick off the first limb:
|
Chris@16
|
31 limb_type limb;
|
Chris@16
|
32 limb_type mask = ~static_cast<limb_type>(0);
|
Chris@16
|
33 From fl;
|
Chris@16
|
34 eval_bitwise_and(fl, t, mask);
|
Chris@16
|
35 eval_convert_to(&limb, fl);
|
Chris@16
|
36 to = static_cast<to_type>(limb);
|
Chris@16
|
37 eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
Chris@16
|
38 //
|
Chris@16
|
39 // Then keep picking off more limbs until "t" is zero:
|
Chris@16
|
40 //
|
Chris@16
|
41 To l;
|
Chris@16
|
42 unsigned shift = std::numeric_limits<limb_type>::digits;
|
Chris@16
|
43 while(!eval_is_zero(t))
|
Chris@16
|
44 {
|
Chris@16
|
45 eval_bitwise_and(fl, t, mask);
|
Chris@16
|
46 eval_convert_to(&limb, fl);
|
Chris@16
|
47 l = static_cast<to_type>(limb);
|
Chris@16
|
48 eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
Chris@16
|
49 eval_ldexp(l, l, shift);
|
Chris@16
|
50 eval_add(to, l);
|
Chris@16
|
51 shift += std::numeric_limits<limb_type>::digits;
|
Chris@16
|
52 }
|
Chris@16
|
53 //
|
Chris@16
|
54 // Finish off by setting the sign:
|
Chris@16
|
55 //
|
Chris@16
|
56 if(is_neg)
|
Chris@16
|
57 to.negate();
|
Chris@16
|
58 }
|
Chris@16
|
59
|
Chris@16
|
60 template <class To, class From>
|
Chris@16
|
61 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
Chris@16
|
62 {
|
Chris@16
|
63 using default_ops::eval_get_sign;
|
Chris@16
|
64 using default_ops::eval_bitwise_and;
|
Chris@16
|
65 using default_ops::eval_convert_to;
|
Chris@16
|
66 using default_ops::eval_right_shift;
|
Chris@16
|
67 using default_ops::eval_left_shift;
|
Chris@16
|
68 using default_ops::eval_bitwise_or;
|
Chris@16
|
69 using default_ops::eval_is_zero;
|
Chris@16
|
70 // smallest unsigned type handled natively by "From" is likely to be it's limb_type:
|
Chris@16
|
71 typedef typename canonical<unsigned char, From>::type limb_type;
|
Chris@16
|
72 // get the corresponding type that we can assign to "To":
|
Chris@16
|
73 typedef typename canonical<limb_type, To>::type to_type;
|
Chris@16
|
74 From t(from);
|
Chris@16
|
75 bool is_neg = eval_get_sign(t) < 0;
|
Chris@16
|
76 if(is_neg)
|
Chris@16
|
77 t.negate();
|
Chris@16
|
78 // Pick off the first limb:
|
Chris@16
|
79 limb_type limb;
|
Chris@16
|
80 limb_type mask = static_cast<limb_type>(~static_cast<limb_type>(0));
|
Chris@16
|
81 From fl;
|
Chris@16
|
82 eval_bitwise_and(fl, t, mask);
|
Chris@16
|
83 eval_convert_to(&limb, fl);
|
Chris@16
|
84 to = static_cast<to_type>(limb);
|
Chris@16
|
85 eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
Chris@16
|
86 //
|
Chris@16
|
87 // Then keep picking off more limbs until "t" is zero:
|
Chris@16
|
88 //
|
Chris@16
|
89 To l;
|
Chris@16
|
90 unsigned shift = std::numeric_limits<limb_type>::digits;
|
Chris@16
|
91 while(!eval_is_zero(t))
|
Chris@16
|
92 {
|
Chris@16
|
93 eval_bitwise_and(fl, t, mask);
|
Chris@16
|
94 eval_convert_to(&limb, fl);
|
Chris@16
|
95 l = static_cast<to_type>(limb);
|
Chris@16
|
96 eval_right_shift(t, std::numeric_limits<limb_type>::digits);
|
Chris@16
|
97 eval_left_shift(l, shift);
|
Chris@16
|
98 eval_bitwise_or(to, l);
|
Chris@16
|
99 shift += std::numeric_limits<limb_type>::digits;
|
Chris@16
|
100 }
|
Chris@16
|
101 //
|
Chris@16
|
102 // Finish off by setting the sign:
|
Chris@16
|
103 //
|
Chris@16
|
104 if(is_neg)
|
Chris@16
|
105 to.negate();
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 template <class To, class From>
|
Chris@16
|
109 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/)
|
Chris@16
|
110 {
|
Chris@16
|
111 #ifdef BOOST_MSVC
|
Chris@16
|
112 #pragma warning(push)
|
Chris@16
|
113 #pragma warning(disable:4127)
|
Chris@16
|
114 #endif
|
Chris@16
|
115 //
|
Chris@16
|
116 // The code here only works when the radix of "From" is 2, we could try shifting by other
|
Chris@16
|
117 // radixes but it would complicate things.... use a string conversion when the radix is other
|
Chris@16
|
118 // than 2:
|
Chris@16
|
119 //
|
Chris@16
|
120 if(std::numeric_limits<number<From> >::radix != 2)
|
Chris@16
|
121 {
|
Chris@16
|
122 to = from.str(0, std::ios_base::fmtflags()).c_str();
|
Chris@16
|
123 return;
|
Chris@16
|
124 }
|
Chris@16
|
125
|
Chris@16
|
126
|
Chris@16
|
127 typedef typename canonical<unsigned char, To>::type ui_type;
|
Chris@16
|
128
|
Chris@16
|
129 using default_ops::eval_fpclassify;
|
Chris@16
|
130 using default_ops::eval_add;
|
Chris@16
|
131 using default_ops::eval_subtract;
|
Chris@16
|
132 using default_ops::eval_convert_to;
|
Chris@16
|
133
|
Chris@16
|
134 //
|
Chris@16
|
135 // First classify the input, then handle the special cases:
|
Chris@16
|
136 //
|
Chris@16
|
137 int c = eval_fpclassify(from);
|
Chris@16
|
138
|
Chris@16
|
139 if(c == FP_ZERO)
|
Chris@16
|
140 {
|
Chris@16
|
141 to = ui_type(0);
|
Chris@16
|
142 return;
|
Chris@16
|
143 }
|
Chris@16
|
144 else if(c == FP_NAN)
|
Chris@16
|
145 {
|
Chris@16
|
146 to = "nan";
|
Chris@16
|
147 return;
|
Chris@16
|
148 }
|
Chris@16
|
149 else if(c == FP_INFINITE)
|
Chris@16
|
150 {
|
Chris@16
|
151 to = "inf";
|
Chris@16
|
152 if(eval_get_sign(from) < 0)
|
Chris@16
|
153 to.negate();
|
Chris@16
|
154 return;
|
Chris@16
|
155 }
|
Chris@16
|
156
|
Chris@16
|
157 typename From::exponent_type e;
|
Chris@16
|
158 From f, term;
|
Chris@16
|
159 to = ui_type(0);
|
Chris@16
|
160
|
Chris@16
|
161 eval_frexp(f, from, &e);
|
Chris@16
|
162
|
Chris@16
|
163 static const int shift = std::numeric_limits<boost::intmax_t>::digits - 1;
|
Chris@16
|
164
|
Chris@16
|
165 while(!eval_is_zero(f))
|
Chris@16
|
166 {
|
Chris@16
|
167 // extract int sized bits from f:
|
Chris@16
|
168 eval_ldexp(f, f, shift);
|
Chris@16
|
169 eval_floor(term, f);
|
Chris@16
|
170 e -= shift;
|
Chris@16
|
171 eval_ldexp(to, to, shift);
|
Chris@16
|
172 typename boost::multiprecision::detail::canonical<boost::intmax_t, To>::type ll;
|
Chris@16
|
173 eval_convert_to(&ll, term);
|
Chris@16
|
174 eval_add(to, ll);
|
Chris@16
|
175 eval_subtract(f, term);
|
Chris@16
|
176 }
|
Chris@16
|
177 typedef typename To::exponent_type to_exponent;
|
Chris@16
|
178 if((e > (std::numeric_limits<to_exponent>::max)()) || (e < (std::numeric_limits<to_exponent>::min)()))
|
Chris@16
|
179 {
|
Chris@16
|
180 to = "inf";
|
Chris@16
|
181 if(eval_get_sign(from) < 0)
|
Chris@16
|
182 to.negate();
|
Chris@16
|
183 return;
|
Chris@16
|
184 }
|
Chris@16
|
185 eval_ldexp(to, to, static_cast<to_exponent>(e));
|
Chris@16
|
186 #ifdef BOOST_MSVC
|
Chris@16
|
187 #pragma warning(pop)
|
Chris@16
|
188 #endif
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 template <class To, class From>
|
Chris@16
|
192 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
Chris@16
|
193 {
|
Chris@16
|
194 typedef typename component_type<number<To> >::type to_component_type;
|
Chris@16
|
195
|
Chris@16
|
196 number<From> t(from);
|
Chris@16
|
197 to_component_type n(numerator(t)), d(denominator(t));
|
Chris@16
|
198 using default_ops::assign_components;
|
Chris@16
|
199 assign_components(to, n.backend(), d.backend());
|
Chris@16
|
200 }
|
Chris@16
|
201
|
Chris@16
|
202 template <class To, class From>
|
Chris@16
|
203 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/)
|
Chris@16
|
204 {
|
Chris@16
|
205 typedef typename component_type<number<To> >::type to_component_type;
|
Chris@16
|
206
|
Chris@16
|
207 number<From> t(from);
|
Chris@16
|
208 to_component_type n(t), d(1);
|
Chris@16
|
209 using default_ops::assign_components;
|
Chris@16
|
210 assign_components(to, n.backend(), d.backend());
|
Chris@16
|
211 }
|
Chris@16
|
212
|
Chris@16
|
213 template <class To, class From>
|
Chris@16
|
214 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/)
|
Chris@16
|
215 {
|
Chris@16
|
216 typedef typename component_type<number<From> >::type from_component_type;
|
Chris@16
|
217 using default_ops::eval_divide;
|
Chris@16
|
218
|
Chris@16
|
219 number<From> t(from);
|
Chris@16
|
220 from_component_type n(numerator(t)), d(denominator(t));
|
Chris@16
|
221 number<To> fn(n), fd(d);
|
Chris@16
|
222 eval_divide(to, fn.backend(), fd.backend());
|
Chris@16
|
223 }
|
Chris@16
|
224
|
Chris@16
|
225 }}} // namespaces
|
Chris@16
|
226
|
Chris@16
|
227 #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP
|
Chris@16
|
228
|