]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright 2011 John Maddock. Distributed under the Boost | |
3 | // Software License, Version 1.0. (See accompanying file | |
4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP | |
7 | #define BOOST_MP_GENERIC_INTERCONVERT_HPP | |
8 | ||
9 | #include <boost/multiprecision/detail/default_ops.hpp> | |
10 | ||
11 | #ifdef BOOST_MSVC | |
12 | #pragma warning(push) | |
92f5a8d4 | 13 | #pragma warning(disable : 4127 6326) |
7c673cae FG |
14 | #endif |
15 | ||
92f5a8d4 | 16 | namespace boost { namespace multiprecision { namespace detail { |
7c673cae FG |
17 | |
18 | template <class To, class From> | |
92f5a8d4 | 19 | inline To do_cast(const From& from) |
7c673cae FG |
20 | { |
21 | return static_cast<To>(from); | |
22 | } | |
23 | template <class To, class B, ::boost::multiprecision::expression_template_option et> | |
24 | inline To do_cast(const number<B, et>& from) | |
25 | { | |
26 | return from.template convert_to<To>(); | |
27 | } | |
28 | ||
29 | template <class To, class From> | |
30 | 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*/) | |
31 | { | |
92f5a8d4 | 32 | using default_ops::eval_add; |
7c673cae FG |
33 | using default_ops::eval_bitwise_and; |
34 | using default_ops::eval_convert_to; | |
92f5a8d4 | 35 | using default_ops::eval_get_sign; |
7c673cae | 36 | using default_ops::eval_is_zero; |
92f5a8d4 TL |
37 | using default_ops::eval_ldexp; |
38 | using default_ops::eval_right_shift; | |
7c673cae | 39 | // smallest unsigned type handled natively by "From" is likely to be it's limb_type: |
92f5a8d4 | 40 | typedef typename canonical<unsigned char, From>::type l_limb_type; |
7c673cae | 41 | // get the corresponding type that we can assign to "To": |
92f5a8d4 TL |
42 | typedef typename canonical<l_limb_type, To>::type to_type; |
43 | From t(from); | |
44 | bool is_neg = eval_get_sign(t) < 0; | |
45 | if (is_neg) | |
7c673cae FG |
46 | t.negate(); |
47 | // Pick off the first limb: | |
48 | l_limb_type limb; | |
49 | l_limb_type mask = static_cast<l_limb_type>(~static_cast<l_limb_type>(0)); | |
92f5a8d4 | 50 | From fl; |
7c673cae FG |
51 | eval_bitwise_and(fl, t, mask); |
52 | eval_convert_to(&limb, fl); | |
53 | to = static_cast<to_type>(limb); | |
54 | eval_right_shift(t, std::numeric_limits<l_limb_type>::digits); | |
55 | // | |
56 | // Then keep picking off more limbs until "t" is zero: | |
57 | // | |
92f5a8d4 | 58 | To l; |
7c673cae | 59 | unsigned shift = std::numeric_limits<l_limb_type>::digits; |
92f5a8d4 | 60 | while (!eval_is_zero(t)) |
7c673cae FG |
61 | { |
62 | eval_bitwise_and(fl, t, mask); | |
63 | eval_convert_to(&limb, fl); | |
64 | l = static_cast<to_type>(limb); | |
65 | eval_right_shift(t, std::numeric_limits<l_limb_type>::digits); | |
66 | eval_ldexp(l, l, shift); | |
67 | eval_add(to, l); | |
68 | shift += std::numeric_limits<l_limb_type>::digits; | |
69 | } | |
70 | // | |
71 | // Finish off by setting the sign: | |
72 | // | |
92f5a8d4 | 73 | if (is_neg) |
7c673cae FG |
74 | to.negate(); |
75 | } | |
76 | ||
77 | template <class To, class From> | |
78 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/) | |
79 | { | |
7c673cae | 80 | using default_ops::eval_bitwise_and; |
7c673cae | 81 | using default_ops::eval_bitwise_or; |
92f5a8d4 TL |
82 | using default_ops::eval_convert_to; |
83 | using default_ops::eval_get_sign; | |
7c673cae | 84 | using default_ops::eval_is_zero; |
92f5a8d4 TL |
85 | using default_ops::eval_left_shift; |
86 | using default_ops::eval_right_shift; | |
7c673cae | 87 | // smallest unsigned type handled natively by "From" is likely to be it's limb_type: |
92f5a8d4 | 88 | typedef typename canonical<unsigned char, From>::type limb_type; |
7c673cae | 89 | // get the corresponding type that we can assign to "To": |
92f5a8d4 TL |
90 | typedef typename canonical<limb_type, To>::type to_type; |
91 | From t(from); | |
92 | bool is_neg = eval_get_sign(t) < 0; | |
93 | if (is_neg) | |
7c673cae FG |
94 | t.negate(); |
95 | // Pick off the first limb: | |
96 | limb_type limb; | |
97 | limb_type mask = static_cast<limb_type>(~static_cast<limb_type>(0)); | |
92f5a8d4 | 98 | From fl; |
7c673cae FG |
99 | eval_bitwise_and(fl, t, mask); |
100 | eval_convert_to(&limb, fl); | |
101 | to = static_cast<to_type>(limb); | |
102 | eval_right_shift(t, std::numeric_limits<limb_type>::digits); | |
103 | // | |
104 | // Then keep picking off more limbs until "t" is zero: | |
105 | // | |
92f5a8d4 | 106 | To l; |
7c673cae | 107 | unsigned shift = std::numeric_limits<limb_type>::digits; |
92f5a8d4 | 108 | while (!eval_is_zero(t)) |
7c673cae FG |
109 | { |
110 | eval_bitwise_and(fl, t, mask); | |
111 | eval_convert_to(&limb, fl); | |
112 | l = static_cast<to_type>(limb); | |
113 | eval_right_shift(t, std::numeric_limits<limb_type>::digits); | |
114 | eval_left_shift(l, shift); | |
115 | eval_bitwise_or(to, l); | |
116 | shift += std::numeric_limits<limb_type>::digits; | |
117 | } | |
118 | // | |
119 | // Finish off by setting the sign: | |
120 | // | |
92f5a8d4 | 121 | if (is_neg) |
7c673cae FG |
122 | to.negate(); |
123 | } | |
124 | ||
125 | template <class To, class From> | |
126 | 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*/) | |
127 | { | |
128 | #ifdef BOOST_MSVC | |
129 | #pragma warning(push) | |
92f5a8d4 | 130 | #pragma warning(disable : 4127) |
7c673cae FG |
131 | #endif |
132 | // | |
133 | // The code here only works when the radix of "From" is 2, we could try shifting by other | |
134 | // radixes but it would complicate things.... use a string conversion when the radix is other | |
135 | // than 2: | |
136 | // | |
92f5a8d4 | 137 | if (std::numeric_limits<number<From> >::radix != 2) |
7c673cae FG |
138 | { |
139 | to = from.str(0, std::ios_base::fmtflags()).c_str(); | |
140 | return; | |
141 | } | |
142 | ||
7c673cae FG |
143 | typedef typename canonical<unsigned char, To>::type ui_type; |
144 | ||
7c673cae | 145 | using default_ops::eval_add; |
7c673cae | 146 | using default_ops::eval_convert_to; |
92f5a8d4 | 147 | using default_ops::eval_fpclassify; |
7c673cae FG |
148 | using default_ops::eval_get_sign; |
149 | using default_ops::eval_is_zero; | |
92f5a8d4 | 150 | using default_ops::eval_subtract; |
7c673cae FG |
151 | |
152 | // | |
153 | // First classify the input, then handle the special cases: | |
154 | // | |
155 | int c = eval_fpclassify(from); | |
156 | ||
92f5a8d4 | 157 | if (c == (int)FP_ZERO) |
7c673cae FG |
158 | { |
159 | to = ui_type(0); | |
160 | return; | |
161 | } | |
92f5a8d4 | 162 | else if (c == (int)FP_NAN) |
7c673cae FG |
163 | { |
164 | to = static_cast<const char*>("nan"); | |
165 | return; | |
166 | } | |
92f5a8d4 | 167 | else if (c == (int)FP_INFINITE) |
7c673cae FG |
168 | { |
169 | to = static_cast<const char*>("inf"); | |
92f5a8d4 | 170 | if (eval_get_sign(from) < 0) |
7c673cae FG |
171 | to.negate(); |
172 | return; | |
173 | } | |
174 | ||
175 | typename From::exponent_type e; | |
92f5a8d4 | 176 | From f, term; |
7c673cae FG |
177 | to = ui_type(0); |
178 | ||
179 | eval_frexp(f, from, &e); | |
180 | ||
181 | static const int shift = std::numeric_limits<boost::intmax_t>::digits - 1; | |
182 | ||
92f5a8d4 | 183 | while (!eval_is_zero(f)) |
7c673cae FG |
184 | { |
185 | // extract int sized bits from f: | |
186 | eval_ldexp(f, f, shift); | |
187 | eval_floor(term, f); | |
188 | e -= shift; | |
189 | eval_ldexp(to, to, shift); | |
190 | typename boost::multiprecision::detail::canonical<boost::intmax_t, To>::type ll; | |
191 | eval_convert_to(&ll, term); | |
192 | eval_add(to, ll); | |
193 | eval_subtract(f, term); | |
194 | } | |
195 | typedef typename To::exponent_type to_exponent; | |
92f5a8d4 | 196 | if (e > (std::numeric_limits<to_exponent>::max)()) |
7c673cae FG |
197 | { |
198 | to = static_cast<const char*>("inf"); | |
92f5a8d4 TL |
199 | if (eval_get_sign(from) < 0) |
200 | to.negate(); | |
201 | return; | |
202 | } | |
203 | if (e < (std::numeric_limits<to_exponent>::min)()) | |
204 | { | |
205 | to = ui_type(0); | |
206 | if (eval_get_sign(from) < 0) | |
7c673cae FG |
207 | to.negate(); |
208 | return; | |
209 | } | |
210 | eval_ldexp(to, to, static_cast<to_exponent>(e)); | |
211 | #ifdef BOOST_MSVC | |
212 | #pragma warning(pop) | |
213 | #endif | |
214 | } | |
215 | ||
216 | template <class To, class From> | |
217 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/) | |
218 | { | |
92f5a8d4 | 219 | typedef typename component_type<number<To> >::type to_component_type; |
7c673cae | 220 | |
92f5a8d4 | 221 | number<From> t(from); |
7c673cae FG |
222 | to_component_type n(numerator(t)), d(denominator(t)); |
223 | using default_ops::assign_components; | |
224 | assign_components(to, n.backend(), d.backend()); | |
225 | } | |
226 | ||
227 | template <class To, class From> | |
228 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/) | |
229 | { | |
92f5a8d4 | 230 | typedef typename component_type<number<To> >::type to_component_type; |
7c673cae | 231 | |
92f5a8d4 | 232 | number<From> t(from); |
7c673cae FG |
233 | to_component_type n(t), d(1); |
234 | using default_ops::assign_components; | |
235 | assign_components(to, n.backend(), d.backend()); | |
236 | } | |
237 | ||
238 | template <class R, class LargeInteger> | |
239 | R safe_convert_to_float(const LargeInteger& i) | |
240 | { | |
241 | using std::ldexp; | |
92f5a8d4 | 242 | if (!i) |
7c673cae | 243 | return R(0); |
92f5a8d4 | 244 | if (std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent) |
7c673cae FG |
245 | { |
246 | LargeInteger val(i); | |
92f5a8d4 | 247 | if (val.sign() < 0) |
7c673cae FG |
248 | val = -val; |
249 | unsigned mb = msb(val); | |
92f5a8d4 | 250 | if (mb >= std::numeric_limits<R>::max_exponent) |
7c673cae FG |
251 | { |
252 | int scale_factor = (int)mb + 1 - std::numeric_limits<R>::max_exponent; | |
253 | BOOST_ASSERT(scale_factor >= 1); | |
254 | val >>= scale_factor; | |
255 | R result = val.template convert_to<R>(); | |
92f5a8d4 | 256 | if (std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent) |
7c673cae FG |
257 | { |
258 | // | |
259 | // Calculate and add on the remainder, only if there are more | |
92f5a8d4 | 260 | // digits in the mantissa that the size of the exponent, in |
7c673cae FG |
261 | // other words if we are dropping digits in the conversion |
262 | // otherwise: | |
263 | // | |
264 | LargeInteger remainder(i); | |
265 | remainder &= (LargeInteger(1) << scale_factor) - 1; | |
266 | result += ldexp(safe_convert_to_float<R>(remainder), -scale_factor); | |
267 | } | |
268 | return i.sign() < 0 ? static_cast<R>(-result) : result; | |
269 | } | |
270 | } | |
271 | return i.template convert_to<R>(); | |
272 | } | |
273 | ||
274 | template <class To, class Integer> | |
92f5a8d4 TL |
275 | inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type |
276 | generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&) | |
7c673cae FG |
277 | { |
278 | // | |
279 | // If we get here, then there's something about one type or the other | |
280 | // that prevents an exactly rounded result from being calculated | |
281 | // (or at least it's not clear how to implement such a thing). | |
282 | // | |
283 | using default_ops::eval_divide; | |
284 | number<To> fn(safe_convert_to_float<number<To> >(n)), fd(safe_convert_to_float<number<To> >(d)); | |
285 | eval_divide(result, fn.backend(), fd.backend()); | |
286 | } | |
287 | template <class To, class Integer> | |
92f5a8d4 TL |
288 | inline typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type |
289 | generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&) | |
7c673cae FG |
290 | { |
291 | // | |
292 | // If we get here, then there's something about one type or the other | |
293 | // that prevents an exactly rounded result from being calculated | |
294 | // (or at least it's not clear how to implement such a thing). | |
295 | // | |
296 | To fd(safe_convert_to_float<To>(d)); | |
297 | result = safe_convert_to_float<To>(n); | |
298 | result /= fd; | |
299 | } | |
300 | ||
301 | template <class To, class Integer> | |
92f5a8d4 TL |
302 | typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type |
303 | generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_&) | |
7c673cae FG |
304 | { |
305 | // | |
306 | // If we get here, then the precision of type To is known, and the integer type is unbounded | |
307 | // so we can use integer division plus manipulation of the remainder to get an exactly | |
308 | // rounded result. | |
309 | // | |
92f5a8d4 | 310 | if (num == 0) |
7c673cae FG |
311 | { |
312 | result = 0; | |
313 | return; | |
314 | } | |
315 | bool s = false; | |
92f5a8d4 | 316 | if (num < 0) |
7c673cae | 317 | { |
92f5a8d4 | 318 | s = true; |
7c673cae FG |
319 | num = -num; |
320 | } | |
321 | int denom_bits = msb(denom); | |
92f5a8d4 TL |
322 | int shift = std::numeric_limits<To>::digits + denom_bits - msb(num); |
323 | if (shift > 0) | |
7c673cae | 324 | num <<= shift; |
92f5a8d4 | 325 | else if (shift < 0) |
7c673cae FG |
326 | denom <<= boost::multiprecision::detail::unsigned_abs(shift); |
327 | Integer q, r; | |
328 | divide_qr(num, denom, q, r); | |
329 | int q_bits = msb(q); | |
92f5a8d4 | 330 | if (q_bits == std::numeric_limits<To>::digits - 1) |
7c673cae FG |
331 | { |
332 | // | |
333 | // Round up if 2 * r > denom: | |
334 | // | |
335 | r <<= 1; | |
336 | int c = r.compare(denom); | |
92f5a8d4 | 337 | if (c > 0) |
7c673cae | 338 | ++q; |
92f5a8d4 | 339 | else if ((c == 0) && (q & 1u)) |
7c673cae FG |
340 | { |
341 | ++q; | |
342 | } | |
343 | } | |
344 | else | |
345 | { | |
346 | BOOST_ASSERT(q_bits == std::numeric_limits<To>::digits); | |
347 | // | |
348 | // We basically already have the rounding info: | |
349 | // | |
92f5a8d4 | 350 | if (q & 1u) |
7c673cae | 351 | { |
92f5a8d4 | 352 | if (r || (q & 2u)) |
7c673cae FG |
353 | ++q; |
354 | } | |
355 | } | |
356 | using std::ldexp; | |
357 | result = do_cast<To>(q); | |
358 | result = ldexp(result, -shift); | |
92f5a8d4 | 359 | if (s) |
7c673cae FG |
360 | result = -result; |
361 | } | |
362 | template <class To, class Integer> | |
363 | inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type | |
92f5a8d4 | 364 | generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag) |
7c673cae FG |
365 | { |
366 | number<To> t; | |
367 | generic_convert_rational_to_float_imp(t, num, denom, tag); | |
368 | result = t.backend(); | |
369 | } | |
370 | ||
371 | template <class To, class From> | |
372 | inline void generic_convert_rational_to_float(To& result, const From& f) | |
373 | { | |
374 | // | |
375 | // Type From is always a Backend to number<>, or an | |
376 | // instance of number<>, but we allow | |
377 | // To to be either a Backend type, or a real number type, | |
378 | // that way we can call this from generic conversions, and | |
379 | // from specific conversions to built in types. | |
380 | // | |
92f5a8d4 TL |
381 | typedef typename mpl::if_c<is_number<From>::value, From, number<From> >::type actual_from_type; |
382 | typedef typename mpl::if_c<is_number<To>::value || is_floating_point<To>::value, To, number<To> >::type actual_to_type; | |
383 | typedef typename component_type<actual_from_type>::type integer_type; | |
384 | typedef mpl::bool_<!std::numeric_limits<integer_type>::is_specialized || std::numeric_limits<integer_type>::is_bounded || !std::numeric_limits<actual_to_type>::is_specialized || !std::numeric_limits<actual_to_type>::is_bounded || (std::numeric_limits<actual_to_type>::radix != 2)> dispatch_tag; | |
7c673cae FG |
385 | |
386 | integer_type n(numerator(static_cast<actual_from_type>(f))), d(denominator(static_cast<actual_from_type>(f))); | |
387 | generic_convert_rational_to_float_imp(result, n, d, dispatch_tag()); | |
388 | } | |
389 | ||
390 | template <class To, class From> | |
391 | inline 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*/) | |
392 | { | |
393 | generic_convert_rational_to_float(to, from); | |
394 | } | |
395 | ||
396 | template <class To, class From> | |
397 | void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/) | |
398 | { | |
399 | typedef typename mpl::front<typename To::unsigned_types>::type ui_type; | |
92f5a8d4 TL |
400 | static const int shift = std::numeric_limits<boost::long_long_type>::digits; |
401 | typename From::exponent_type e; | |
402 | typename component_type<number<To> >::type num, denom; | |
403 | number<From> val(from); | |
7c673cae | 404 | val = frexp(val, &e); |
92f5a8d4 | 405 | while (val) |
7c673cae FG |
406 | { |
407 | val = ldexp(val, shift); | |
408 | e -= shift; | |
409 | boost::long_long_type ll = boost::math::lltrunc(val); | |
410 | val -= ll; | |
411 | num <<= shift; | |
412 | num += ll; | |
413 | } | |
414 | denom = ui_type(1u); | |
92f5a8d4 | 415 | if (e < 0) |
7c673cae | 416 | denom <<= -e; |
92f5a8d4 | 417 | else if (e > 0) |
7c673cae FG |
418 | num <<= e; |
419 | assign_components(to, num.backend(), denom.backend()); | |
420 | } | |
421 | ||
422 | template <class To, class From, int Radix> | |
423 | void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<Radix>& /*radix*/) | |
424 | { | |
425 | // | |
426 | // This is almost the same as the binary case above, but we have to use | |
427 | // scalbn and ilogb rather than ldexp and frexp, we also only extract | |
428 | // one Radix digit at a time which is terribly inefficient! | |
429 | // | |
430 | typedef typename mpl::front<typename To::unsigned_types>::type ui_type; | |
92f5a8d4 TL |
431 | typename From::exponent_type e; |
432 | typename component_type<number<To> >::type num, denom; | |
433 | number<From> val(from); | |
11fdf7f2 TL |
434 | |
435 | if (!val) | |
436 | { | |
437 | to = ui_type(0u); | |
438 | return; | |
439 | } | |
440 | ||
92f5a8d4 | 441 | e = ilogb(val); |
7c673cae | 442 | val = scalbn(val, -e); |
92f5a8d4 | 443 | while (val) |
7c673cae FG |
444 | { |
445 | boost::long_long_type ll = boost::math::lltrunc(val); | |
446 | val -= ll; | |
447 | val = scalbn(val, 1); | |
448 | num *= Radix; | |
449 | num += ll; | |
450 | --e; | |
451 | } | |
452 | ++e; | |
453 | denom = ui_type(Radix); | |
454 | denom = pow(denom, abs(e)); | |
92f5a8d4 | 455 | if (e > 0) |
7c673cae FG |
456 | { |
457 | num *= denom; | |
458 | denom = 1; | |
459 | } | |
460 | assign_components(to, num.backend(), denom.backend()); | |
461 | } | |
462 | ||
463 | template <class To, class From> | |
464 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/) | |
465 | { | |
466 | generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>()); | |
467 | } | |
468 | ||
469 | template <class To, class From> | |
470 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/) | |
471 | { | |
472 | number<From> t(from); | |
92f5a8d4 | 473 | number<To> result(numerator(t) / denominator(t)); |
7c673cae FG |
474 | to = result.backend(); |
475 | } | |
476 | ||
477 | template <class To, class From> | |
478 | void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2>& /*radix*/) | |
479 | { | |
480 | typedef typename From::exponent_type exponent_type; | |
92f5a8d4 TL |
481 | static const exponent_type shift = std::numeric_limits<boost::long_long_type>::digits; |
482 | exponent_type e; | |
483 | number<To> num(0u); | |
484 | number<From> val(from); | |
485 | val = frexp(val, &e); | |
486 | bool neg = false; | |
487 | if (val.sign() < 0) | |
488 | { | |
489 | val.backend().negate(); | |
490 | neg = true; | |
491 | } | |
492 | while (e > 0) | |
7c673cae | 493 | { |
92f5a8d4 TL |
494 | exponent_type s = (std::min)(e, shift); |
495 | val = ldexp(val, s); | |
7c673cae FG |
496 | e -= s; |
497 | boost::long_long_type ll = boost::math::lltrunc(val); | |
498 | val -= ll; | |
499 | num <<= s; | |
500 | num += ll; | |
501 | } | |
502 | to = num.backend(); | |
92f5a8d4 TL |
503 | if (neg) |
504 | to.negate(); | |
7c673cae FG |
505 | } |
506 | ||
507 | template <class To, class From, int Radix> | |
508 | void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<Radix>& /*radix*/) | |
509 | { | |
510 | // | |
511 | // This is almost the same as the binary case above, but we have to use | |
512 | // scalbn and ilogb rather than ldexp and frexp, we also only extract | |
513 | // one Radix digit at a time which is terribly inefficient! | |
514 | // | |
515 | typename From::exponent_type e; | |
92f5a8d4 TL |
516 | number<To> num(0u); |
517 | number<From> val(from); | |
518 | e = ilogb(val); | |
7c673cae | 519 | val = scalbn(val, -e); |
92f5a8d4 | 520 | while (e >= 0) |
7c673cae FG |
521 | { |
522 | boost::long_long_type ll = boost::math::lltrunc(val); | |
523 | val -= ll; | |
524 | val = scalbn(val, 1); | |
525 | num *= Radix; | |
526 | num += ll; | |
527 | --e; | |
528 | } | |
529 | to = num.backend(); | |
530 | } | |
531 | ||
532 | template <class To, class From> | |
533 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/) | |
534 | { | |
535 | generic_interconvert_float2int(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>()); | |
536 | } | |
537 | ||
92f5a8d4 TL |
538 | template <class To, class From, class tag> |
539 | void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::true_&, const tag&) | |
540 | { | |
541 | // We just want the real part, and "to" is the correct type already: | |
542 | eval_real(to, from); | |
543 | ||
544 | To im; | |
545 | eval_imag(im, from); | |
546 | if (!eval_is_zero(im)) | |
547 | BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar.")); | |
7c673cae | 548 | } |
92f5a8d4 TL |
549 | template <class To, class From> |
550 | void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::true_&) | |
551 | { | |
552 | typedef typename component_type<number<From> >::type component_number; | |
553 | typedef typename component_number::backend_type component_backend; | |
554 | // | |
555 | // Get the real part and copy-construct the result from it: | |
556 | // | |
557 | component_backend r; | |
558 | generic_interconvert_complex_to_scalar(r, from, mpl::true_(), mpl::true_()); | |
559 | to = r; | |
560 | } | |
561 | template <class To, class From> | |
562 | void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::false_&) | |
563 | { | |
564 | typedef typename component_type<number<From> >::type component_number; | |
565 | typedef typename component_number::backend_type component_backend; | |
566 | // | |
567 | // Get the real part and use a generic_interconvert to type To: | |
568 | // | |
569 | component_backend r; | |
570 | generic_interconvert_complex_to_scalar(r, from, mpl::true_(), mpl::true_()); | |
571 | generic_interconvert(to, r, mpl::int_<number_category<To>::value>(), mpl::int_<number_category<To>::value>()); | |
572 | } | |
573 | ||
574 | template <class To, class From> | |
575 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_complex>& /*from_type*/) | |
576 | { | |
577 | typedef typename component_type<number<From> >::type component_number; | |
578 | typedef typename component_number::backend_type component_backend; | |
579 | ||
580 | generic_interconvert_complex_to_scalar(to, from, mpl::bool_<boost::is_same<component_backend, To>::value>(), mpl::bool_<boost::is_constructible<To, const component_backend&>::value>()); | |
581 | } | |
582 | template <class To, class From> | |
583 | void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_integer>& /*to_type*/, const mpl::int_<number_kind_complex>& /*from_type*/) | |
584 | { | |
585 | typedef typename component_type<number<From> >::type component_number; | |
586 | typedef typename component_number::backend_type component_backend; | |
587 | ||
588 | generic_interconvert_complex_to_scalar(to, from, mpl::bool_<boost::is_same<component_backend, To>::value>(), mpl::bool_<boost::is_constructible<To, const component_backend&>::value>()); | |
7c673cae | 589 | } |
92f5a8d4 TL |
590 | |
591 | } | |
592 | } | |
593 | } // namespace boost::multiprecision::detail | |
7c673cae FG |
594 | |
595 | #ifdef BOOST_MSVC | |
596 | #pragma warning(pop) | |
597 | #endif | |
598 | ||
92f5a8d4 | 599 | #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP |