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)
6 #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP
7 #define BOOST_MP_GENERIC_INTERCONVERT_HPP
9 #include <boost/multiprecision/detail/default_ops.hpp>
13 #pragma warning(disable : 4127 6326)
16 namespace boost { namespace multiprecision { namespace detail {
18 template <class To, class From>
19 inline To do_cast(const From& from)
21 return static_cast<To>(from);
23 template <class To, class B, ::boost::multiprecision::expression_template_option et>
24 inline To do_cast(const number<B, et>& from)
26 return from.template convert_to<To>();
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*/)
32 using default_ops::eval_add;
33 using default_ops::eval_bitwise_and;
34 using default_ops::eval_convert_to;
35 using default_ops::eval_get_sign;
36 using default_ops::eval_is_zero;
37 using default_ops::eval_ldexp;
38 using default_ops::eval_right_shift;
39 // smallest unsigned type handled natively by "From" is likely to be it's limb_type:
40 typedef typename canonical<unsigned char, From>::type l_limb_type;
41 // get the corresponding type that we can assign to "To":
42 typedef typename canonical<l_limb_type, To>::type to_type;
44 bool is_neg = eval_get_sign(t) < 0;
47 // Pick off the first limb:
49 l_limb_type mask = static_cast<l_limb_type>(~static_cast<l_limb_type>(0));
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);
56 // Then keep picking off more limbs until "t" is zero:
59 unsigned shift = std::numeric_limits<l_limb_type>::digits;
60 while (!eval_is_zero(t))
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);
68 shift += std::numeric_limits<l_limb_type>::digits;
71 // Finish off by setting the sign:
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*/)
80 using default_ops::eval_bitwise_and;
81 using default_ops::eval_bitwise_or;
82 using default_ops::eval_convert_to;
83 using default_ops::eval_get_sign;
84 using default_ops::eval_is_zero;
85 using default_ops::eval_left_shift;
86 using default_ops::eval_right_shift;
87 // smallest unsigned type handled natively by "From" is likely to be it's limb_type:
88 typedef typename canonical<unsigned char, From>::type limb_type;
89 // get the corresponding type that we can assign to "To":
90 typedef typename canonical<limb_type, To>::type to_type;
92 bool is_neg = eval_get_sign(t) < 0;
95 // Pick off the first limb:
97 limb_type mask = static_cast<limb_type>(~static_cast<limb_type>(0));
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);
104 // Then keep picking off more limbs until "t" is zero:
107 unsigned shift = std::numeric_limits<limb_type>::digits;
108 while (!eval_is_zero(t))
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;
119 // Finish off by setting the sign:
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*/)
129 #pragma warning(push)
130 #pragma warning(disable : 4127)
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
137 if (std::numeric_limits<number<From> >::radix != 2)
139 to = from.str(0, std::ios_base::fmtflags()).c_str();
143 typedef typename canonical<unsigned char, To>::type ui_type;
145 using default_ops::eval_add;
146 using default_ops::eval_convert_to;
147 using default_ops::eval_fpclassify;
148 using default_ops::eval_get_sign;
149 using default_ops::eval_is_zero;
150 using default_ops::eval_subtract;
153 // First classify the input, then handle the special cases:
155 int c = eval_fpclassify(from);
157 if (c == (int)FP_ZERO)
162 else if (c == (int)FP_NAN)
164 to = static_cast<const char*>("nan");
167 else if (c == (int)FP_INFINITE)
169 to = static_cast<const char*>("inf");
170 if (eval_get_sign(from) < 0)
175 typename From::exponent_type e;
179 eval_frexp(f, from, &e);
181 static const int shift = std::numeric_limits<boost::intmax_t>::digits - 1;
183 while (!eval_is_zero(f))
185 // extract int sized bits from f:
186 eval_ldexp(f, f, 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);
193 eval_subtract(f, term);
195 typedef typename To::exponent_type to_exponent;
196 if (e > (std::numeric_limits<to_exponent>::max)())
198 to = static_cast<const char*>("inf");
199 if (eval_get_sign(from) < 0)
203 if (e < (std::numeric_limits<to_exponent>::min)())
206 if (eval_get_sign(from) < 0)
210 eval_ldexp(to, to, static_cast<to_exponent>(e));
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*/)
219 typedef typename component_type<number<To> >::type to_component_type;
221 number<From> t(from);
222 to_component_type n(numerator(t)), d(denominator(t));
223 using default_ops::assign_components;
224 assign_components(to, n.backend(), d.backend());
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*/)
230 typedef typename component_type<number<To> >::type to_component_type;
232 number<From> t(from);
233 to_component_type n(t), d(1);
234 using default_ops::assign_components;
235 assign_components(to, n.backend(), d.backend());
238 template <class R, class LargeInteger>
239 R safe_convert_to_float(const LargeInteger& i)
244 if (std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent)
249 unsigned mb = msb(val);
250 if (mb >= std::numeric_limits<R>::max_exponent)
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>();
256 if (std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent)
259 // Calculate and add on the remainder, only if there are more
260 // digits in the mantissa that the size of the exponent, in
261 // other words if we are dropping digits in the conversion
264 LargeInteger remainder(i);
265 remainder &= (LargeInteger(1) << scale_factor) - 1;
266 result += ldexp(safe_convert_to_float<R>(remainder), -scale_factor);
268 return i.sign() < 0 ? static_cast<R>(-result) : result;
271 return i.template convert_to<R>();
274 template <class To, class Integer>
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_&)
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).
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());
287 template <class To, class Integer>
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_&)
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).
296 To fd(safe_convert_to_float<To>(d));
297 result = safe_convert_to_float<To>(n);
301 template <class To, class Integer>
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_&)
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
321 int denom_bits = msb(denom);
322 int shift = std::numeric_limits<To>::digits + denom_bits - msb(num);
326 denom <<= boost::multiprecision::detail::unsigned_abs(shift);
328 divide_qr(num, denom, q, r);
330 if (q_bits == std::numeric_limits<To>::digits - 1)
333 // Round up if 2 * r > denom:
336 int c = r.compare(denom);
339 else if ((c == 0) && (q & 1u))
346 BOOST_ASSERT(q_bits == std::numeric_limits<To>::digits);
348 // We basically already have the rounding info:
357 result = do_cast<To>(q);
358 result = ldexp(result, -shift);
362 template <class To, class Integer>
363 inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type
364 generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag)
367 generic_convert_rational_to_float_imp(t, num, denom, tag);
368 result = t.backend();
371 template <class To, class From>
372 inline void generic_convert_rational_to_float(To& result, const From& f)
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.
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;
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());
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*/)
393 generic_convert_rational_to_float(to, from);
396 template <class To, class From>
397 void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/)
399 typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
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);
404 val = frexp(val, &e);
407 val = ldexp(val, shift);
409 boost::long_long_type ll = boost::math::lltrunc(val);
419 assign_components(to, num.backend(), denom.backend());
422 template <class To, class From, int Radix>
423 void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
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!
430 typedef typename mpl::front<typename To::unsigned_types>::type ui_type;
431 typename From::exponent_type e;
432 typename component_type<number<To> >::type num, denom;
433 number<From> val(from);
442 val = scalbn(val, -e);
445 boost::long_long_type ll = boost::math::lltrunc(val);
447 val = scalbn(val, 1);
453 denom = ui_type(Radix);
454 denom = pow(denom, abs(e));
460 assign_components(to, num.backend(), denom.backend());
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*/)
466 generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
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*/)
472 number<From> t(from);
473 number<To> result(numerator(t) / denominator(t));
474 to = result.backend();
477 template <class To, class From>
478 void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<2>& /*radix*/)
480 typedef typename From::exponent_type exponent_type;
481 static const exponent_type shift = std::numeric_limits<boost::long_long_type>::digits;
484 number<From> val(from);
485 val = frexp(val, &e);
489 val.backend().negate();
494 exponent_type s = (std::min)(e, shift);
497 boost::long_long_type ll = boost::math::lltrunc(val);
507 template <class To, class From, int Radix>
508 void generic_interconvert_float2int(To& to, const From& from, const mpl::int_<Radix>& /*radix*/)
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!
515 typename From::exponent_type e;
517 number<From> val(from);
519 val = scalbn(val, -e);
522 boost::long_long_type ll = boost::math::lltrunc(val);
524 val = scalbn(val, 1);
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*/)
535 generic_interconvert_float2int(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>());
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&)
541 // We just want the real part, and "to" is the correct type already:
546 if (!eval_is_zero(im))
547 BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert imaginary number to scalar."));
549 template <class To, class From>
550 void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::true_&)
552 typedef typename component_type<number<From> >::type component_number;
553 typedef typename component_number::backend_type component_backend;
555 // Get the real part and copy-construct the result from it:
558 generic_interconvert_complex_to_scalar(r, from, mpl::true_(), mpl::true_());
561 template <class To, class From>
562 void generic_interconvert_complex_to_scalar(To& to, const From& from, const mpl::false_&, const mpl::false_&)
564 typedef typename component_type<number<From> >::type component_number;
565 typedef typename component_number::backend_type component_backend;
567 // Get the real part and use a generic_interconvert to type To:
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>());
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*/)
577 typedef typename component_type<number<From> >::type component_number;
578 typedef typename component_number::backend_type component_backend;
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>());
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*/)
585 typedef typename component_type<number<From> >::type component_number;
586 typedef typename component_number::backend_type component_backend;
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>());
593 } // namespace boost::multiprecision::detail
599 #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP