annotate DEPENDENCIES/generic/include/boost/multiprecision/detail/generic_interconvert.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
rev   line source
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