Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Copyright 2011 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP Chris@16: #define BOOST_MP_GENERIC_INTERCONVERT_HPP Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost{ namespace multiprecision{ namespace detail{ Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: using default_ops::eval_bitwise_and; Chris@16: using default_ops::eval_convert_to; Chris@16: using default_ops::eval_right_shift; Chris@16: using default_ops::eval_ldexp; Chris@16: using default_ops::eval_add; Chris@16: // smallest unsigned type handled natively by "From" is likely to be it's limb_type: Chris@16: typedef typename canonical::type limb_type; Chris@16: // get the corresponding type that we can assign to "To": Chris@16: typedef typename canonical::type to_type; Chris@16: From t(from); Chris@16: bool is_neg = eval_get_sign(t) < 0; Chris@16: if(is_neg) Chris@16: t.negate(); Chris@16: // Pick off the first limb: Chris@16: limb_type limb; Chris@16: limb_type mask = ~static_cast(0); Chris@16: From fl; Chris@16: eval_bitwise_and(fl, t, mask); Chris@16: eval_convert_to(&limb, fl); Chris@16: to = static_cast(limb); Chris@16: eval_right_shift(t, std::numeric_limits::digits); Chris@16: // Chris@16: // Then keep picking off more limbs until "t" is zero: Chris@16: // Chris@16: To l; Chris@16: unsigned shift = std::numeric_limits::digits; Chris@16: while(!eval_is_zero(t)) Chris@16: { Chris@16: eval_bitwise_and(fl, t, mask); Chris@16: eval_convert_to(&limb, fl); Chris@16: l = static_cast(limb); Chris@16: eval_right_shift(t, std::numeric_limits::digits); Chris@16: eval_ldexp(l, l, shift); Chris@16: eval_add(to, l); Chris@16: shift += std::numeric_limits::digits; Chris@16: } Chris@16: // Chris@16: // Finish off by setting the sign: Chris@16: // Chris@16: if(is_neg) Chris@16: to.negate(); Chris@16: } Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: using default_ops::eval_bitwise_and; Chris@16: using default_ops::eval_convert_to; Chris@16: using default_ops::eval_right_shift; Chris@16: using default_ops::eval_left_shift; Chris@16: using default_ops::eval_bitwise_or; Chris@16: using default_ops::eval_is_zero; Chris@16: // smallest unsigned type handled natively by "From" is likely to be it's limb_type: Chris@16: typedef typename canonical::type limb_type; Chris@16: // get the corresponding type that we can assign to "To": Chris@16: typedef typename canonical::type to_type; Chris@16: From t(from); Chris@16: bool is_neg = eval_get_sign(t) < 0; Chris@16: if(is_neg) Chris@16: t.negate(); Chris@16: // Pick off the first limb: Chris@16: limb_type limb; Chris@16: limb_type mask = static_cast(~static_cast(0)); Chris@16: From fl; Chris@16: eval_bitwise_and(fl, t, mask); Chris@16: eval_convert_to(&limb, fl); Chris@16: to = static_cast(limb); Chris@16: eval_right_shift(t, std::numeric_limits::digits); Chris@16: // Chris@16: // Then keep picking off more limbs until "t" is zero: Chris@16: // Chris@16: To l; Chris@16: unsigned shift = std::numeric_limits::digits; Chris@16: while(!eval_is_zero(t)) Chris@16: { Chris@16: eval_bitwise_and(fl, t, mask); Chris@16: eval_convert_to(&limb, fl); Chris@16: l = static_cast(limb); Chris@16: eval_right_shift(t, std::numeric_limits::digits); Chris@16: eval_left_shift(l, shift); Chris@16: eval_bitwise_or(to, l); Chris@16: shift += std::numeric_limits::digits; Chris@16: } Chris@16: // Chris@16: // Finish off by setting the sign: Chris@16: // Chris@16: if(is_neg) Chris@16: to.negate(); Chris@16: } Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4127) Chris@16: #endif Chris@16: // Chris@16: // The code here only works when the radix of "From" is 2, we could try shifting by other Chris@16: // radixes but it would complicate things.... use a string conversion when the radix is other Chris@16: // than 2: Chris@16: // Chris@16: if(std::numeric_limits >::radix != 2) Chris@16: { Chris@16: to = from.str(0, std::ios_base::fmtflags()).c_str(); Chris@16: return; Chris@16: } Chris@16: Chris@16: Chris@16: typedef typename canonical::type ui_type; Chris@16: Chris@16: using default_ops::eval_fpclassify; Chris@16: using default_ops::eval_add; Chris@16: using default_ops::eval_subtract; Chris@16: using default_ops::eval_convert_to; Chris@16: Chris@16: // Chris@16: // First classify the input, then handle the special cases: Chris@16: // Chris@16: int c = eval_fpclassify(from); Chris@16: Chris@16: if(c == FP_ZERO) Chris@16: { Chris@16: to = ui_type(0); Chris@16: return; Chris@16: } Chris@16: else if(c == FP_NAN) Chris@16: { Chris@16: to = "nan"; Chris@16: return; Chris@16: } Chris@16: else if(c == FP_INFINITE) Chris@16: { Chris@16: to = "inf"; Chris@16: if(eval_get_sign(from) < 0) Chris@16: to.negate(); Chris@16: return; Chris@16: } Chris@16: Chris@16: typename From::exponent_type e; Chris@16: From f, term; Chris@16: to = ui_type(0); Chris@16: Chris@16: eval_frexp(f, from, &e); Chris@16: Chris@16: static const int shift = std::numeric_limits::digits - 1; Chris@16: Chris@16: while(!eval_is_zero(f)) Chris@16: { Chris@16: // extract int sized bits from f: Chris@16: eval_ldexp(f, f, shift); Chris@16: eval_floor(term, f); Chris@16: e -= shift; Chris@16: eval_ldexp(to, to, shift); Chris@16: typename boost::multiprecision::detail::canonical::type ll; Chris@16: eval_convert_to(&ll, term); Chris@16: eval_add(to, ll); Chris@16: eval_subtract(f, term); Chris@16: } Chris@16: typedef typename To::exponent_type to_exponent; Chris@16: if((e > (std::numeric_limits::max)()) || (e < (std::numeric_limits::min)())) Chris@16: { Chris@16: to = "inf"; Chris@16: if(eval_get_sign(from) < 0) Chris@16: to.negate(); Chris@16: return; Chris@16: } Chris@16: eval_ldexp(to, to, static_cast(e)); Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: } Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: typedef typename component_type >::type to_component_type; Chris@16: Chris@16: number t(from); Chris@16: to_component_type n(numerator(t)), d(denominator(t)); Chris@16: using default_ops::assign_components; Chris@16: assign_components(to, n.backend(), d.backend()); Chris@16: } Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: typedef typename component_type >::type to_component_type; Chris@16: Chris@16: number t(from); Chris@16: to_component_type n(t), d(1); Chris@16: using default_ops::assign_components; Chris@16: assign_components(to, n.backend(), d.backend()); Chris@16: } Chris@16: Chris@16: template Chris@16: void generic_interconvert(To& to, const From& from, const mpl::int_& /*to_type*/, const mpl::int_& /*from_type*/) Chris@16: { Chris@16: typedef typename component_type >::type from_component_type; Chris@16: using default_ops::eval_divide; Chris@16: Chris@16: number t(from); Chris@16: from_component_type n(numerator(t)), d(denominator(t)); Chris@16: number fn(n), fd(d); Chris@16: eval_divide(to, fn.backend(), fd.backend()); Chris@16: } Chris@16: Chris@16: }}} // namespaces Chris@16: Chris@16: #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP Chris@16: