generic_interconvert.hpp 7.1 KB

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