]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/multiprecision/detail/generic_interconvert.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / multiprecision / detail / generic_interconvert.hpp
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)
13 #pragma warning(disable : 4127 6326)
14 #endif
15
16 namespace boost { namespace multiprecision { namespace detail {
17
18 template <class To, class From>
19 inline To do_cast(const From& from)
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 {
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;
43 From t(from);
44 bool is_neg = eval_get_sign(t) < 0;
45 if (is_neg)
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));
50 From fl;
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 //
58 To l;
59 unsigned shift = std::numeric_limits<l_limb_type>::digits;
60 while (!eval_is_zero(t))
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 //
73 if (is_neg)
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 {
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;
91 From t(from);
92 bool is_neg = eval_get_sign(t) < 0;
93 if (is_neg)
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));
98 From fl;
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 //
106 To l;
107 unsigned shift = std::numeric_limits<limb_type>::digits;
108 while (!eval_is_zero(t))
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 //
121 if (is_neg)
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)
130 #pragma warning(disable : 4127)
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 //
137 if (std::numeric_limits<number<From> >::radix != 2)
138 {
139 to = from.str(0, std::ios_base::fmtflags()).c_str();
140 return;
141 }
142
143 typedef typename canonical<unsigned char, To>::type ui_type;
144
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;
151
152 //
153 // First classify the input, then handle the special cases:
154 //
155 int c = eval_fpclassify(from);
156
157 if (c == (int)FP_ZERO)
158 {
159 to = ui_type(0);
160 return;
161 }
162 else if (c == (int)FP_NAN)
163 {
164 to = static_cast<const char*>("nan");
165 return;
166 }
167 else if (c == (int)FP_INFINITE)
168 {
169 to = static_cast<const char*>("inf");
170 if (eval_get_sign(from) < 0)
171 to.negate();
172 return;
173 }
174
175 typename From::exponent_type e;
176 From f, term;
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
183 while (!eval_is_zero(f))
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;
196 if (e > (std::numeric_limits<to_exponent>::max)())
197 {
198 to = static_cast<const char*>("inf");
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)
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 {
219 typedef typename component_type<number<To> >::type to_component_type;
220
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());
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 {
230 typedef typename component_type<number<To> >::type to_component_type;
231
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());
236 }
237
238 template <class R, class LargeInteger>
239 R safe_convert_to_float(const LargeInteger& i)
240 {
241 using std::ldexp;
242 if (!i)
243 return R(0);
244 if (std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent)
245 {
246 LargeInteger val(i);
247 if (val.sign() < 0)
248 val = -val;
249 unsigned mb = msb(val);
250 if (mb >= std::numeric_limits<R>::max_exponent)
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>();
256 if (std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent)
257 {
258 //
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
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>
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_&)
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>
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_&)
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>
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_&)
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 //
310 if (num == 0)
311 {
312 result = 0;
313 return;
314 }
315 bool s = false;
316 if (num < 0)
317 {
318 s = true;
319 num = -num;
320 }
321 int denom_bits = msb(denom);
322 int shift = std::numeric_limits<To>::digits + denom_bits - msb(num);
323 if (shift > 0)
324 num <<= shift;
325 else if (shift < 0)
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);
330 if (q_bits == std::numeric_limits<To>::digits - 1)
331 {
332 //
333 // Round up if 2 * r > denom:
334 //
335 r <<= 1;
336 int c = r.compare(denom);
337 if (c > 0)
338 ++q;
339 else if ((c == 0) && (q & 1u))
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 //
350 if (q & 1u)
351 {
352 if (r || (q & 2u))
353 ++q;
354 }
355 }
356 using std::ldexp;
357 result = do_cast<To>(q);
358 result = ldexp(result, -shift);
359 if (s)
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
364 generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag)
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 //
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;
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;
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);
405 while (val)
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);
415 if (e < 0)
416 denom <<= -e;
417 else if (e > 0)
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;
431 typename From::exponent_type e;
432 typename component_type<number<To> >::type num, denom;
433 number<From> val(from);
434
435 if (!val)
436 {
437 to = ui_type(0u);
438 return;
439 }
440
441 e = ilogb(val);
442 val = scalbn(val, -e);
443 while (val)
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));
455 if (e > 0)
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);
473 number<To> result(numerator(t) / denominator(t));
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;
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)
493 {
494 exponent_type s = (std::min)(e, shift);
495 val = ldexp(val, s);
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();
503 if (neg)
504 to.negate();
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;
516 number<To> num(0u);
517 number<From> val(from);
518 e = ilogb(val);
519 val = scalbn(val, -e);
520 while (e >= 0)
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
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."));
548 }
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>());
589 }
590
591 }
592 }
593 } // namespace boost::multiprecision::detail
594
595 #ifdef BOOST_MSVC
596 #pragma warning(pop)
597 #endif
598
599 #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP