• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
do_cast(const From & 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>
do_cast(const number<B,et> & from)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_floating_point> &,const mpl::int_<number_kind_integer> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_integer> &,const mpl::int_<number_kind_integer> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_floating_point> &,const mpl::int_<number_kind_floating_point> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_rational> &,const mpl::int_<number_kind_rational> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_rational> &,const mpl::int_<number_kind_integer> &)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>
safe_convert_to_float(const LargeInteger & i)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
generic_convert_rational_to_float_imp(To & result,const Integer & n,const Integer & d,const mpl::true_ &)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
generic_convert_rational_to_float_imp(To & result,const Integer & n,const Integer & d,const mpl::true_ &)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
generic_convert_rational_to_float_imp(To & result,Integer & num,Integer & denom,const mpl::false_ &)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
generic_convert_rational_to_float_imp(To & result,Integer & num,Integer & denom,const mpl::false_ & tag)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>
generic_convert_rational_to_float(To & result,const From & f)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_floating_point> &,const mpl::int_<number_kind_rational> &)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>
generic_interconvert_float2rational(To & to,const From & from,const mpl::int_<2> &)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>
generic_interconvert_float2rational(To & to,const From & from,const mpl::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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_rational> &,const mpl::int_<number_kind_floating_point> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_integer> &,const mpl::int_<number_kind_rational> &)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>
generic_interconvert_float2int(To & to,const From & from,const mpl::int_<2> &)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>
generic_interconvert_float2int(To & to,const From & from,const mpl::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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_integer> &,const mpl::int_<number_kind_floating_point> &)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>
generic_interconvert_complex_to_scalar(To & to,const From & from,const mpl::true_ &,const 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>
generic_interconvert_complex_to_scalar(To & to,const From & from,const mpl::false_ &,const mpl::true_ &)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>
generic_interconvert_complex_to_scalar(To & to,const From & from,const mpl::false_ &,const mpl::false_ &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_floating_point> &,const mpl::int_<number_kind_complex> &)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>
generic_interconvert(To & to,const From & from,const mpl::int_<number_kind_integer> &,const mpl::int_<number_kind_complex> &)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
600