]>
Commit | Line | Data |
---|---|---|
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_MATH_BIG_NUM_BASE_HPP | |
7 | #define BOOST_MATH_BIG_NUM_BASE_HPP | |
8 | ||
9 | #include <limits> | |
10 | #include <boost/utility/enable_if.hpp> | |
11 | #include <boost/type_traits/is_convertible.hpp> | |
12 | #include <boost/type_traits/is_constructible.hpp> | |
13 | #include <boost/type_traits/decay.hpp> | |
14 | #ifdef BOOST_MSVC | |
15 | # pragma warning(push) | |
16 | # pragma warning(disable:4307) | |
17 | #endif | |
18 | #include <boost/lexical_cast.hpp> | |
19 | #ifdef BOOST_MSVC | |
20 | # pragma warning(pop) | |
21 | #endif | |
22 | ||
23 | #if defined(NDEBUG) && !defined(_DEBUG) | |
24 | # define BOOST_MP_FORCEINLINE BOOST_FORCEINLINE | |
25 | #else | |
26 | # define BOOST_MP_FORCEINLINE inline | |
27 | #endif | |
28 | ||
29 | #if (defined(BOOST_GCC) && (BOOST_GCC <= 40700)) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140) | |
30 | # define BOOST_MP_NOEXCEPT_IF(x) | |
31 | #else | |
32 | # define BOOST_MP_NOEXCEPT_IF(x) BOOST_NOEXCEPT_IF(x) | |
33 | #endif | |
34 | ||
35 | #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) || BOOST_WORKAROUND(__SUNPRO_CC, < 0x5140) | |
36 | #define BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
37 | #endif | |
38 | ||
39 | // | |
40 | // Thread local storage: | |
41 | // | |
42 | #if !defined(BOOST_NO_CXX11_THREAD_LOCAL) && !defined(BOOST_INTEL) | |
43 | # define BOOST_MP_THREAD_LOCAL thread_local | |
44 | #else | |
45 | # define BOOST_MP_THREAD_LOCAL | |
46 | #endif | |
47 | ||
48 | #ifdef BOOST_MSVC | |
49 | # pragma warning(push) | |
50 | # pragma warning(disable:6326) | |
51 | #endif | |
52 | ||
53 | namespace boost{ | |
54 | namespace multiprecision{ | |
55 | ||
56 | enum expression_template_option | |
57 | { | |
58 | et_off = 0, | |
59 | et_on = 1 | |
60 | }; | |
61 | ||
62 | template <class Backend> | |
63 | struct expression_template_default | |
64 | { | |
65 | static const expression_template_option value = et_on; | |
66 | }; | |
67 | ||
68 | template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value> | |
69 | class number; | |
70 | ||
71 | template <class T> | |
72 | struct is_number : public mpl::false_ {}; | |
73 | ||
74 | template <class Backend, expression_template_option ExpressionTemplates> | |
75 | struct is_number<number<Backend, ExpressionTemplates> > : public mpl::true_ {}; | |
76 | ||
77 | template <class T> | |
78 | struct is_et_number : public mpl::false_ {}; | |
79 | ||
80 | template <class Backend> | |
81 | struct is_et_number<number<Backend, et_on> > : public mpl::true_ {}; | |
82 | ||
83 | template <class T> | |
84 | struct is_no_et_number : public mpl::false_ {}; | |
85 | ||
86 | template <class Backend> | |
87 | struct is_no_et_number<number<Backend, et_off> > : public mpl::true_ {}; | |
88 | ||
89 | namespace detail{ | |
90 | ||
91 | // Forward-declare an expression wrapper | |
92 | template<class tag, class Arg1 = void, class Arg2 = void, class Arg3 = void, class Arg4 = void> | |
93 | struct expression; | |
94 | ||
95 | } // namespace detail | |
96 | ||
97 | template <class T> | |
98 | struct is_number_expression : public mpl::false_ {}; | |
99 | ||
100 | template<class tag, class Arg1, class Arg2, class Arg3, class Arg4> | |
101 | struct is_number_expression<detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public mpl::true_ {}; | |
102 | ||
103 | template <class T, class Num> | |
104 | struct is_compatible_arithmetic_type | |
105 | : public mpl::bool_< | |
106 | is_convertible<T, Num>::value | |
107 | && !is_same<T, Num>::value | |
108 | && !is_number_expression<T>::value> | |
109 | {}; | |
110 | ||
111 | namespace detail{ | |
112 | // | |
113 | // Workaround for missing abs(boost::long_long_type) and abs(__int128) on some compilers: | |
114 | // | |
115 | template <class T> | |
116 | BOOST_CONSTEXPR typename enable_if_c<(is_signed<T>::value || is_floating_point<T>::value), T>::type abs(T t) BOOST_NOEXCEPT | |
117 | { | |
118 | // This strange expression avoids a hardware trap in the corner case | |
119 | // that val is the most negative value permitted in boost::long_long_type. | |
120 | // See https://svn.boost.org/trac/boost/ticket/9740. | |
121 | return t < 0 ? T(1u) + T(-(t + 1)) : t; | |
122 | } | |
123 | template <class T> | |
124 | BOOST_CONSTEXPR typename enable_if_c<(is_unsigned<T>::value), T>::type abs(T t) BOOST_NOEXCEPT | |
125 | { | |
126 | return t; | |
127 | } | |
128 | ||
129 | #define BOOST_MP_USING_ABS using boost::multiprecision::detail::abs; | |
130 | ||
131 | template <class T> | |
132 | BOOST_CONSTEXPR typename enable_if_c<(is_signed<T>::value || is_floating_point<T>::value), typename make_unsigned<T>::type>::type unsigned_abs(T t) BOOST_NOEXCEPT | |
133 | { | |
134 | // This strange expression avoids a hardware trap in the corner case | |
135 | // that val is the most negative value permitted in boost::long_long_type. | |
136 | // See https://svn.boost.org/trac/boost/ticket/9740. | |
137 | return t < 0 ? static_cast<typename make_unsigned<T>::type>(1u) + static_cast<typename make_unsigned<T>::type>(-(t + 1)) : static_cast<typename make_unsigned<T>::type>(t); | |
138 | } | |
139 | template <class T> | |
140 | BOOST_CONSTEXPR typename enable_if_c<(is_unsigned<T>::value), T>::type unsigned_abs(T t) BOOST_NOEXCEPT | |
141 | { | |
142 | return t; | |
143 | } | |
144 | ||
145 | // | |
146 | // Move support: | |
147 | // | |
148 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
149 | # define BOOST_MP_MOVE(x) std::move(x) | |
150 | #else | |
151 | # define BOOST_MP_MOVE(x) x | |
152 | #endif | |
153 | ||
154 | template <class T> | |
155 | struct bits_of | |
156 | { | |
157 | BOOST_STATIC_ASSERT(is_integral<T>::value || is_enum<T>::value || std::numeric_limits<T>::is_specialized); | |
158 | static const unsigned value = | |
159 | std::numeric_limits<T>::is_specialized ? | |
160 | std::numeric_limits<T>::digits | |
161 | : sizeof(T) * CHAR_BIT - (is_signed<T>::value ? 1 : 0); | |
162 | }; | |
163 | ||
164 | #if defined(_GLIBCXX_USE_FLOAT128) && defined(BOOST_GCC) && !defined(__STRICT_ANSI__) | |
165 | template<> struct bits_of<__float128> { static const unsigned value = 113; }; | |
166 | #endif | |
167 | ||
168 | template <int b> | |
169 | struct has_enough_bits | |
170 | { | |
171 | template <class T> | |
172 | struct type : public mpl::bool_<bits_of<T>::value>= b>{}; | |
173 | }; | |
174 | ||
175 | template <class Val, class Backend, class Tag> | |
176 | struct canonical_imp | |
177 | { | |
178 | typedef typename remove_cv<typename decay<const Val>::type>::type type; | |
179 | }; | |
180 | template <class B, class Backend, class Tag> | |
181 | struct canonical_imp<number<B, et_on>, Backend, Tag> | |
182 | { | |
183 | typedef B type; | |
184 | }; | |
185 | template <class B, class Backend, class Tag> | |
186 | struct canonical_imp<number<B, et_off>, Backend, Tag> | |
187 | { | |
188 | typedef B type; | |
189 | }; | |
190 | #ifdef __SUNPRO_CC | |
191 | template <class B, class Backend> | |
192 | struct canonical_imp<number<B, et_on>, Backend, mpl::int_<3> > | |
193 | { | |
194 | typedef B type; | |
195 | }; | |
196 | template <class B, class Backend> | |
197 | struct canonical_imp<number<B, et_off>, Backend, mpl::int_<3> > | |
198 | { | |
199 | typedef B type; | |
200 | }; | |
201 | #endif | |
202 | template <class Val, class Backend> | |
203 | struct canonical_imp<Val, Backend, mpl::int_<0> > | |
204 | { | |
205 | typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type; | |
206 | typedef typename mpl::find_if< | |
207 | typename Backend::signed_types, | |
208 | pred_type | |
209 | >::type iter_type; | |
210 | typedef typename mpl::end<typename Backend::signed_types>::type end_type; | |
211 | typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type; | |
212 | }; | |
213 | template <class Val, class Backend> | |
214 | struct canonical_imp<Val, Backend, mpl::int_<1> > | |
215 | { | |
216 | typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type; | |
217 | typedef typename mpl::find_if< | |
218 | typename Backend::unsigned_types, | |
219 | pred_type | |
220 | >::type iter_type; | |
221 | typedef typename mpl::end<typename Backend::unsigned_types>::type end_type; | |
222 | typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type; | |
223 | }; | |
224 | template <class Val, class Backend> | |
225 | struct canonical_imp<Val, Backend, mpl::int_<2> > | |
226 | { | |
227 | typedef typename has_enough_bits<bits_of<Val>::value>::template type<mpl::_> pred_type; | |
228 | typedef typename mpl::find_if< | |
229 | typename Backend::float_types, | |
230 | pred_type | |
231 | >::type iter_type; | |
232 | typedef typename mpl::end<typename Backend::float_types>::type end_type; | |
233 | typedef typename mpl::eval_if<boost::is_same<iter_type, end_type>, mpl::identity<Val>, mpl::deref<iter_type> >::type type; | |
234 | }; | |
235 | template <class Val, class Backend> | |
236 | struct canonical_imp<Val, Backend, mpl::int_<3> > | |
237 | { | |
238 | typedef const char* type; | |
239 | }; | |
240 | ||
241 | template <class Val, class Backend> | |
242 | struct canonical | |
243 | { | |
244 | typedef typename mpl::if_< | |
245 | is_signed<Val>, | |
246 | mpl::int_<0>, | |
247 | typename mpl::if_< | |
248 | is_unsigned<Val>, | |
249 | mpl::int_<1>, | |
250 | typename mpl::if_< | |
251 | is_floating_point<Val>, | |
252 | mpl::int_<2>, | |
253 | typename mpl::if_< | |
254 | mpl::or_< | |
255 | is_convertible<Val, const char*>, | |
256 | is_same<Val, std::string> | |
257 | >, | |
258 | mpl::int_<3>, | |
259 | mpl::int_<4> | |
260 | >::type | |
261 | >::type | |
262 | >::type | |
263 | >::type tag_type; | |
264 | ||
265 | typedef typename canonical_imp<Val, Backend, tag_type>::type type; | |
266 | }; | |
267 | ||
268 | struct terminal{}; | |
269 | struct negate{}; | |
270 | struct plus{}; | |
271 | struct minus{}; | |
272 | struct multiplies{}; | |
273 | struct divides{}; | |
274 | struct modulus{}; | |
275 | struct shift_left{}; | |
276 | struct shift_right{}; | |
277 | struct bitwise_and{}; | |
278 | struct bitwise_or{}; | |
279 | struct bitwise_xor{}; | |
280 | struct bitwise_complement{}; | |
281 | struct add_immediates{}; | |
282 | struct subtract_immediates{}; | |
283 | struct multiply_immediates{}; | |
284 | struct divide_immediates{}; | |
285 | struct modulus_immediates{}; | |
286 | struct bitwise_and_immediates{}; | |
287 | struct bitwise_or_immediates{}; | |
288 | struct bitwise_xor_immediates{}; | |
289 | struct complement_immediates{}; | |
290 | struct function{}; | |
291 | struct multiply_add{}; | |
292 | struct multiply_subtract{}; | |
293 | ||
294 | template <class T> | |
295 | struct backend_type; | |
296 | ||
297 | template <class T, expression_template_option ExpressionTemplates> | |
298 | struct backend_type<number<T, ExpressionTemplates> > | |
299 | { | |
300 | typedef T type; | |
301 | }; | |
302 | ||
303 | template <class tag, class A1, class A2, class A3, class A4> | |
304 | struct backend_type<expression<tag, A1, A2, A3, A4> > | |
305 | { | |
306 | typedef typename backend_type<typename expression<tag, A1, A2, A3, A4>::result_type>::type type; | |
307 | }; | |
308 | ||
309 | ||
310 | template <class T1, class T2> | |
311 | struct combine_expression | |
312 | { | |
313 | #ifdef BOOST_NO_CXX11_DECLTYPE | |
314 | typedef typename mpl::if_c<(sizeof(T1() + T2()) == sizeof(T1)), T1, T2>::type type; | |
315 | #else | |
316 | typedef decltype(T1() + T2()) type; | |
317 | #endif | |
318 | }; | |
319 | ||
320 | template <class T1, expression_template_option ExpressionTemplates, class T2> | |
321 | struct combine_expression<number<T1, ExpressionTemplates>, T2> | |
322 | { | |
323 | typedef number<T1, ExpressionTemplates> type; | |
324 | }; | |
325 | ||
326 | template <class T1, class T2, expression_template_option ExpressionTemplates> | |
327 | struct combine_expression<T1, number<T2, ExpressionTemplates> > | |
328 | { | |
329 | typedef number<T2, ExpressionTemplates> type; | |
330 | }; | |
331 | ||
332 | template <class T, expression_template_option ExpressionTemplates> | |
333 | struct combine_expression<number<T, ExpressionTemplates>, number<T, ExpressionTemplates> > | |
334 | { | |
335 | typedef number<T, ExpressionTemplates> type; | |
336 | }; | |
337 | ||
338 | template <class T1, expression_template_option ExpressionTemplates1, class T2, expression_template_option ExpressionTemplates2> | |
339 | struct combine_expression<number<T1, ExpressionTemplates1>, number<T2, ExpressionTemplates2> > | |
340 | { | |
341 | typedef typename mpl::if_c< | |
342 | is_convertible<number<T2, ExpressionTemplates2>, number<T1, ExpressionTemplates2> >::value, | |
343 | number<T1, ExpressionTemplates1>, | |
344 | number<T2, ExpressionTemplates2> | |
345 | >::type type; | |
346 | }; | |
347 | ||
348 | template <class T> | |
349 | struct arg_type | |
350 | { | |
351 | typedef expression<terminal, T> type; | |
352 | }; | |
353 | ||
354 | template <class Tag, class Arg1, class Arg2, class Arg3, class Arg4> | |
355 | struct arg_type<expression<Tag, Arg1, Arg2, Arg3, Arg4> > | |
356 | { | |
357 | typedef expression<Tag, Arg1, Arg2, Arg3, Arg4> type; | |
358 | }; | |
359 | ||
360 | struct unmentionable | |
361 | { | |
362 | unmentionable* proc(){ return 0; } | |
363 | }; | |
364 | ||
365 | typedef unmentionable* (unmentionable::*unmentionable_type)(); | |
366 | ||
367 | template <class T> | |
368 | struct expression_storage | |
369 | { | |
370 | typedef const T& type; | |
371 | }; | |
372 | ||
373 | template <class T> | |
374 | struct expression_storage<T*> | |
375 | { | |
376 | typedef T* type; | |
377 | }; | |
378 | ||
379 | template <class T> | |
380 | struct expression_storage<const T*> | |
381 | { | |
382 | typedef const T* type; | |
383 | }; | |
384 | ||
385 | template <class tag, class A1, class A2, class A3, class A4> | |
386 | struct expression_storage<expression<tag, A1, A2, A3, A4> > | |
387 | { | |
388 | typedef expression<tag, A1, A2, A3, A4> type; | |
389 | }; | |
390 | ||
391 | template<class tag, class Arg1> | |
392 | struct expression<tag, Arg1, void, void, void> | |
393 | { | |
394 | typedef mpl::int_<1> arity; | |
395 | typedef typename arg_type<Arg1>::type left_type; | |
396 | typedef typename left_type::result_type left_result_type; | |
397 | typedef typename left_type::result_type result_type; | |
398 | typedef tag tag_type; | |
399 | ||
400 | explicit expression(const Arg1& a) : arg(a) {} | |
401 | ||
402 | left_type left()const { return left_type(arg); } | |
403 | ||
404 | const Arg1& left_ref()const BOOST_NOEXCEPT { return arg; } | |
405 | ||
406 | static const unsigned depth = left_type::depth + 1; | |
407 | #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
408 | # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) | |
409 | // | |
410 | // Horrible workaround for gcc-4.6.x which always prefers the template | |
411 | // operator bool() rather than the non-template operator when converting to | |
412 | // an arithmetic type: | |
413 | // | |
414 | template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> | |
415 | explicit operator T ()const | |
416 | { | |
417 | result_type r(*this); | |
418 | return static_cast<bool>(r); | |
419 | } | |
420 | template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0> | |
421 | explicit operator T ()const | |
422 | { | |
423 | return static_cast<T>(static_cast<result_type>(*this)); | |
424 | } | |
425 | # else | |
426 | template <class T | |
427 | #ifndef __SUNPRO_CC | |
428 | , typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 | |
429 | #endif | |
430 | > | |
431 | explicit operator T()const | |
432 | { | |
433 | return static_cast<T>(static_cast<result_type>(*this)); | |
434 | } | |
435 | BOOST_MP_FORCEINLINE explicit operator bool()const | |
436 | { | |
437 | result_type r(*this); | |
438 | return static_cast<bool>(r); | |
439 | } | |
440 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) | |
441 | BOOST_MP_FORCEINLINE explicit operator void()const {} | |
442 | #endif | |
443 | # endif | |
444 | #else | |
445 | operator unmentionable_type()const | |
446 | { | |
447 | result_type r(*this); | |
448 | return r ? &unmentionable::proc : 0; | |
449 | } | |
450 | #endif | |
451 | ||
452 | template <class T> | |
453 | T convert_to() | |
454 | { | |
455 | result_type r(*this); | |
456 | return r.template convert_to<T>(); | |
457 | } | |
458 | ||
459 | private: | |
460 | typename expression_storage<Arg1>::type arg; | |
461 | expression& operator=(const expression&); | |
462 | }; | |
463 | ||
464 | template<class Arg1> | |
465 | struct expression<terminal, Arg1, void, void, void> | |
466 | { | |
467 | typedef mpl::int_<0> arity; | |
468 | typedef Arg1 result_type; | |
469 | typedef terminal tag_type; | |
470 | ||
471 | explicit expression(const Arg1& a) : arg(a) {} | |
472 | ||
473 | const Arg1& value()const BOOST_NOEXCEPT { return arg; } | |
474 | ||
475 | static const unsigned depth = 0; | |
476 | ||
477 | #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
478 | # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) | |
479 | // | |
480 | // Horrible workaround for gcc-4.6.x which always prefers the template | |
481 | // operator bool() rather than the non-template operator when converting to | |
482 | // an arithmetic type: | |
483 | // | |
484 | template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> | |
485 | explicit operator T ()const | |
486 | { | |
487 | result_type r(*this); | |
488 | return static_cast<bool>(r); | |
489 | } | |
490 | template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0> | |
491 | explicit operator T ()const | |
492 | { | |
493 | return static_cast<T>(static_cast<result_type>(*this)); | |
494 | } | |
495 | # else | |
496 | template <class T | |
497 | #ifndef __SUNPRO_CC | |
498 | , typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 | |
499 | #endif | |
500 | > | |
501 | explicit operator T()const | |
502 | { | |
503 | return static_cast<T>(static_cast<result_type>(*this)); | |
504 | } | |
505 | BOOST_MP_FORCEINLINE explicit operator bool()const | |
506 | { | |
507 | result_type r(*this); | |
508 | return static_cast<bool>(r); | |
509 | } | |
510 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) | |
511 | BOOST_MP_FORCEINLINE explicit operator void()const {} | |
512 | #endif | |
513 | # endif | |
514 | #else | |
515 | operator unmentionable_type()const | |
516 | { | |
517 | return arg ? &unmentionable::proc : 0; | |
518 | } | |
519 | #endif | |
520 | ||
521 | template <class T> | |
522 | T convert_to() | |
523 | { | |
524 | result_type r(*this); | |
525 | return r.template convert_to<T>(); | |
526 | } | |
527 | ||
528 | private: | |
529 | typename expression_storage<Arg1>::type arg; | |
530 | expression& operator=(const expression&); | |
531 | }; | |
532 | ||
533 | template <class tag, class Arg1, class Arg2> | |
534 | struct expression<tag, Arg1, Arg2, void, void> | |
535 | { | |
536 | typedef mpl::int_<2> arity; | |
537 | typedef typename arg_type<Arg1>::type left_type; | |
538 | typedef typename arg_type<Arg2>::type right_type; | |
539 | typedef typename left_type::result_type left_result_type; | |
540 | typedef typename right_type::result_type right_result_type; | |
541 | typedef typename combine_expression<left_result_type, right_result_type>::type result_type; | |
542 | typedef tag tag_type; | |
543 | ||
544 | expression(const Arg1& a1, const Arg2& a2) : arg1(a1), arg2(a2) {} | |
545 | ||
546 | left_type left()const { return left_type(arg1); } | |
547 | right_type right()const { return right_type(arg2); } | |
548 | const Arg1& left_ref()const BOOST_NOEXCEPT { return arg1; } | |
549 | const Arg2& right_ref()const BOOST_NOEXCEPT { return arg2; } | |
550 | ||
551 | #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
552 | # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) | |
553 | // | |
554 | // Horrible workaround for gcc-4.6.x which always prefers the template | |
555 | // operator bool() rather than the non-template operator when converting to | |
556 | // an arithmetic type: | |
557 | // | |
558 | template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> | |
559 | explicit operator T ()const | |
560 | { | |
561 | result_type r(*this); | |
562 | return static_cast<bool>(r); | |
563 | } | |
564 | template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0> | |
565 | explicit operator T ()const | |
566 | { | |
567 | return static_cast<T>(static_cast<result_type>(*this)); | |
568 | } | |
569 | # else | |
570 | template <class T | |
571 | #ifndef __SUNPRO_CC | |
572 | , typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 | |
573 | #endif | |
574 | > | |
575 | explicit operator T()const | |
576 | { | |
577 | return static_cast<T>(static_cast<result_type>(*this)); | |
578 | } | |
579 | BOOST_MP_FORCEINLINE explicit operator bool()const | |
580 | { | |
581 | result_type r(*this); | |
582 | return static_cast<bool>(r); | |
583 | } | |
584 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) | |
585 | BOOST_MP_FORCEINLINE explicit operator void()const {} | |
586 | #endif | |
587 | # endif | |
588 | #else | |
589 | operator unmentionable_type()const | |
590 | { | |
591 | result_type r(*this); | |
592 | return r ? &unmentionable::proc : 0; | |
593 | } | |
594 | #endif | |
595 | template <class T> | |
596 | T convert_to() | |
597 | { | |
598 | result_type r(*this); | |
599 | return r.template convert_to<T>(); | |
600 | } | |
601 | ||
602 | static const unsigned left_depth = left_type::depth + 1; | |
603 | static const unsigned right_depth = right_type::depth + 1; | |
604 | static const unsigned depth = left_depth > right_depth ? left_depth : right_depth; | |
605 | private: | |
606 | typename expression_storage<Arg1>::type arg1; | |
607 | typename expression_storage<Arg2>::type arg2; | |
608 | expression& operator=(const expression&); | |
609 | }; | |
610 | ||
611 | template <class tag, class Arg1, class Arg2, class Arg3> | |
612 | struct expression<tag, Arg1, Arg2, Arg3, void> | |
613 | { | |
614 | typedef mpl::int_<3> arity; | |
615 | typedef typename arg_type<Arg1>::type left_type; | |
616 | typedef typename arg_type<Arg2>::type middle_type; | |
617 | typedef typename arg_type<Arg3>::type right_type; | |
618 | typedef typename left_type::result_type left_result_type; | |
619 | typedef typename middle_type::result_type middle_result_type; | |
620 | typedef typename right_type::result_type right_result_type; | |
621 | typedef typename combine_expression< | |
622 | left_result_type, | |
623 | typename combine_expression<right_result_type, middle_result_type>::type | |
624 | >::type result_type; | |
625 | typedef tag tag_type; | |
626 | ||
627 | expression(const Arg1& a1, const Arg2& a2, const Arg3& a3) : arg1(a1), arg2(a2), arg3(a3) {} | |
628 | ||
629 | left_type left()const { return left_type(arg1); } | |
630 | middle_type middle()const { return middle_type(arg2); } | |
631 | right_type right()const { return right_type(arg3); } | |
632 | const Arg1& left_ref()const BOOST_NOEXCEPT { return arg1; } | |
633 | const Arg2& middle_ref()const BOOST_NOEXCEPT { return arg2; } | |
634 | const Arg3& right_ref()const BOOST_NOEXCEPT { return arg3; } | |
635 | ||
636 | #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
637 | # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) | |
638 | // | |
639 | // Horrible workaround for gcc-4.6.x which always prefers the template | |
640 | // operator bool() rather than the non-template operator when converting to | |
641 | // an arithmetic type: | |
642 | // | |
643 | template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> | |
644 | explicit operator T ()const | |
645 | { | |
646 | result_type r(*this); | |
647 | return static_cast<bool>(r); | |
648 | } | |
649 | template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0> | |
650 | explicit operator T ()const | |
651 | { | |
652 | return static_cast<T>(static_cast<result_type>(*this)); | |
653 | } | |
654 | # else | |
655 | template <class T | |
656 | #ifndef __SUNPRO_CC | |
657 | , typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 | |
658 | #endif | |
659 | > | |
660 | explicit operator T()const | |
661 | { | |
662 | return static_cast<T>(static_cast<result_type>(*this)); | |
663 | } | |
664 | BOOST_MP_FORCEINLINE explicit operator bool()const | |
665 | { | |
666 | result_type r(*this); | |
667 | return static_cast<bool>(r); | |
668 | } | |
669 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) | |
670 | BOOST_MP_FORCEINLINE explicit operator void()const {} | |
671 | #endif | |
672 | # endif | |
673 | #else | |
674 | operator unmentionable_type()const | |
675 | { | |
676 | result_type r(*this); | |
677 | return r ? &unmentionable::proc : 0; | |
678 | } | |
679 | #endif | |
680 | template <class T> | |
681 | T convert_to() | |
682 | { | |
683 | result_type r(*this); | |
684 | return r.template convert_to<T>(); | |
685 | } | |
686 | ||
687 | static const unsigned left_depth = left_type::depth + 1; | |
688 | static const unsigned middle_depth = middle_type::depth + 1; | |
689 | static const unsigned right_depth = right_type::depth + 1; | |
690 | static const unsigned depth = left_depth > right_depth ? (left_depth > middle_depth ? left_depth : middle_depth) : (right_depth > middle_depth ? right_depth : middle_depth); | |
691 | private: | |
692 | typename expression_storage<Arg1>::type arg1; | |
693 | typename expression_storage<Arg2>::type arg2; | |
694 | typename expression_storage<Arg3>::type arg3; | |
695 | expression& operator=(const expression&); | |
696 | }; | |
697 | ||
698 | template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> | |
699 | struct expression | |
700 | { | |
701 | typedef mpl::int_<4> arity; | |
702 | typedef typename arg_type<Arg1>::type left_type; | |
703 | typedef typename arg_type<Arg2>::type left_middle_type; | |
704 | typedef typename arg_type<Arg3>::type right_middle_type; | |
705 | typedef typename arg_type<Arg4>::type right_type; | |
706 | typedef typename left_type::result_type left_result_type; | |
707 | typedef typename left_middle_type::result_type left_middle_result_type; | |
708 | typedef typename right_middle_type::result_type right_middle_result_type; | |
709 | typedef typename right_type::result_type right_result_type; | |
710 | typedef typename combine_expression< | |
711 | left_result_type, | |
712 | typename combine_expression< | |
713 | left_middle_result_type, | |
714 | typename combine_expression<right_middle_result_type, right_result_type>::type | |
715 | >::type | |
716 | >::type result_type; | |
717 | typedef tag tag_type; | |
718 | ||
719 | expression(const Arg1& a1, const Arg2& a2, const Arg3& a3, const Arg4& a4) : arg1(a1), arg2(a2), arg3(a3), arg4(a4) {} | |
720 | ||
721 | left_type left()const { return left_type(arg1); } | |
722 | left_middle_type left_middle()const { return left_middle_type(arg2); } | |
723 | right_middle_type right_middle()const { return right_middle_type(arg3); } | |
724 | right_type right()const { return right_type(arg4); } | |
725 | const Arg1& left_ref()const BOOST_NOEXCEPT { return arg1; } | |
726 | const Arg2& left_middle_ref()const BOOST_NOEXCEPT { return arg2; } | |
727 | const Arg3& right_middle_ref()const BOOST_NOEXCEPT { return arg3; } | |
728 | const Arg4& right_ref()const BOOST_NOEXCEPT { return arg4; } | |
729 | ||
730 | #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
731 | # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7) && !defined(__clang__)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) | |
732 | // | |
733 | // Horrible workaround for gcc-4.6.x which always prefers the template | |
734 | // operator bool() rather than the non-template operator when converting to | |
735 | // an arithmetic type: | |
736 | // | |
737 | template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0> | |
738 | explicit operator T ()const | |
739 | { | |
740 | result_type r(*this); | |
741 | return static_cast<bool>(r); | |
742 | } | |
743 | template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0> | |
744 | explicit operator T ()const | |
745 | { | |
746 | return static_cast<T>(static_cast<result_type>(*this)); | |
747 | } | |
748 | # else | |
749 | template <class T | |
750 | #ifndef __SUNPRO_CC | |
751 | , typename boost::disable_if_c<is_number<T>::value || is_constructible<T const&, result_type>::value, int>::type = 0 | |
752 | #endif | |
753 | > | |
754 | explicit operator T()const | |
755 | { | |
756 | return static_cast<T>(static_cast<result_type>(*this)); | |
757 | } | |
758 | BOOST_MP_FORCEINLINE explicit operator bool()const | |
759 | { | |
760 | result_type r(*this); | |
761 | return static_cast<bool>(r); | |
762 | } | |
763 | #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) | |
764 | BOOST_MP_FORCEINLINE explicit operator void()const {} | |
765 | #endif | |
766 | # endif | |
767 | #else | |
768 | operator unmentionable_type()const | |
769 | { | |
770 | result_type r(*this); | |
771 | return r ? &unmentionable::proc : 0; | |
772 | } | |
773 | #endif | |
774 | template <class T> | |
775 | T convert_to() | |
776 | { | |
777 | result_type r(*this); | |
778 | return r.template convert_to<T>(); | |
779 | } | |
780 | ||
781 | static const unsigned left_depth = left_type::depth + 1; | |
782 | static const unsigned left_middle_depth = left_middle_type::depth + 1; | |
783 | static const unsigned right_middle_depth = right_middle_type::depth + 1; | |
784 | static const unsigned right_depth = right_type::depth + 1; | |
785 | ||
786 | static const unsigned left_max_depth = left_depth > left_middle_depth ? left_depth : left_middle_depth; | |
787 | static const unsigned right_max_depth = right_depth > right_middle_depth ? right_depth : right_middle_depth; | |
788 | ||
789 | static const unsigned depth = left_max_depth > right_max_depth ? left_max_depth : right_max_depth; | |
790 | private: | |
791 | typename expression_storage<Arg1>::type arg1; | |
792 | typename expression_storage<Arg2>::type arg2; | |
793 | typename expression_storage<Arg3>::type arg3; | |
794 | typename expression_storage<Arg4>::type arg4; | |
795 | expression& operator=(const expression&); | |
796 | }; | |
797 | ||
798 | template <class T> | |
799 | struct digits2 | |
800 | { | |
801 | BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized); | |
802 | BOOST_STATIC_ASSERT((std::numeric_limits<T>::radix == 2) || (std::numeric_limits<T>::radix == 10)); | |
803 | // If we really have so many digits that this fails, then we're probably going to hit other problems anyway: | |
804 | BOOST_STATIC_ASSERT(LONG_MAX / 1000 > (std::numeric_limits<T>::digits + 1)); | |
805 | static const long m_value = std::numeric_limits<T>::radix == 10 ? (((std::numeric_limits<T>::digits + 1) * 1000L) / 301L) : std::numeric_limits<T>::digits; | |
806 | static inline BOOST_CONSTEXPR long value()BOOST_NOEXCEPT { return m_value; } | |
807 | }; | |
808 | ||
809 | #ifndef BOOST_MP_MIN_EXPONENT_DIGITS | |
810 | #ifdef _MSC_VER | |
811 | # define BOOST_MP_MIN_EXPONENT_DIGITS 2 | |
812 | #else | |
813 | # define BOOST_MP_MIN_EXPONENT_DIGITS 2 | |
814 | #endif | |
815 | #endif | |
816 | ||
817 | template <class S> | |
818 | void format_float_string(S& str, boost::intmax_t my_exp, boost::intmax_t digits, std::ios_base::fmtflags f, bool iszero) | |
819 | { | |
820 | typedef typename S::size_type size_type; | |
821 | bool scientific = (f & std::ios_base::scientific) == std::ios_base::scientific; | |
822 | bool fixed = (f & std::ios_base::fixed) == std::ios_base::fixed; | |
823 | bool showpoint = (f & std::ios_base::showpoint) == std::ios_base::showpoint; | |
824 | bool showpos = (f & std::ios_base::showpos) == std::ios_base::showpos; | |
825 | ||
826 | bool neg = str.size() && (str[0] == '-'); | |
827 | ||
828 | if(neg) | |
829 | str.erase(0, 1); | |
830 | ||
831 | if(digits == 0) | |
832 | { | |
833 | digits = (std::max)(str.size(), size_type(16)); | |
834 | } | |
835 | ||
836 | if(iszero || str.empty() || (str.find_first_not_of('0') == S::npos)) | |
837 | { | |
838 | // We will be printing zero, even though the value might not | |
839 | // actually be zero (it just may have been rounded to zero). | |
840 | str = "0"; | |
841 | if(scientific || fixed) | |
842 | { | |
843 | str.append(1, '.'); | |
844 | str.append(size_type(digits), '0'); | |
845 | if(scientific) | |
846 | str.append("e+00"); | |
847 | } | |
848 | else | |
849 | { | |
850 | if(showpoint) | |
851 | { | |
852 | str.append(1, '.'); | |
853 | if(digits > 1) | |
854 | str.append(size_type(digits - 1), '0'); | |
855 | } | |
856 | } | |
857 | if(neg) | |
858 | str.insert(static_cast<std::string::size_type>(0), 1, '-'); | |
859 | else if(showpos) | |
860 | str.insert(static_cast<std::string::size_type>(0), 1, '+'); | |
861 | return; | |
862 | } | |
863 | ||
864 | if(!fixed && !scientific && !showpoint) | |
865 | { | |
866 | // | |
867 | // Suppress trailing zeros: | |
868 | // | |
869 | std::string::iterator pos = str.end(); | |
870 | while(pos != str.begin() && *--pos == '0'){} | |
871 | if(pos != str.end()) | |
872 | ++pos; | |
873 | str.erase(pos, str.end()); | |
874 | if(str.empty()) | |
875 | str = '0'; | |
876 | } | |
877 | else if(!fixed || (my_exp >= 0)) | |
878 | { | |
879 | // | |
880 | // Pad out the end with zero's if we need to: | |
881 | // | |
882 | boost::intmax_t chars = str.size(); | |
883 | chars = digits - chars; | |
884 | if(scientific) | |
885 | ++chars; | |
886 | if(chars > 0) | |
887 | { | |
888 | str.append(static_cast<std::string::size_type>(chars), '0'); | |
889 | } | |
890 | } | |
891 | ||
892 | if(fixed || (!scientific && (my_exp >= -4) && (my_exp < digits))) | |
893 | { | |
894 | if(1 + my_exp > static_cast<boost::intmax_t>(str.size())) | |
895 | { | |
896 | // Just pad out the end with zeros: | |
897 | str.append(static_cast<std::string::size_type>(1 + my_exp - str.size()), '0'); | |
898 | if(showpoint || fixed) | |
899 | str.append("."); | |
900 | } | |
901 | else if(my_exp + 1 < static_cast<boost::intmax_t>(str.size())) | |
902 | { | |
903 | if(my_exp < 0) | |
904 | { | |
905 | str.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(-1 - my_exp), '0'); | |
906 | str.insert(static_cast<std::string::size_type>(0), "0."); | |
907 | } | |
908 | else | |
909 | { | |
910 | // Insert the decimal point: | |
911 | str.insert(static_cast<std::string::size_type>(my_exp + 1), 1, '.'); | |
912 | } | |
913 | } | |
914 | else if(showpoint || fixed) // we have exactly the digits we require to left of the point | |
915 | str += "."; | |
916 | ||
917 | if(fixed) | |
918 | { | |
919 | // We may need to add trailing zeros: | |
920 | boost::intmax_t l = str.find('.') + 1; | |
921 | l = digits - (str.size() - l); | |
922 | if(l > 0) | |
923 | str.append(size_type(l), '0'); | |
924 | } | |
925 | } | |
926 | else | |
927 | { | |
928 | BOOST_MP_USING_ABS | |
929 | // Scientific format: | |
930 | if(showpoint || (str.size() > 1)) | |
931 | str.insert(static_cast<std::string::size_type>(1u), 1, '.'); | |
932 | str.append(static_cast<std::string::size_type>(1u), 'e'); | |
933 | S e = boost::lexical_cast<S>(abs(my_exp)); | |
934 | if(e.size() < BOOST_MP_MIN_EXPONENT_DIGITS) | |
935 | e.insert(static_cast<std::string::size_type>(0), BOOST_MP_MIN_EXPONENT_DIGITS - e.size(), '0'); | |
936 | if(my_exp < 0) | |
937 | e.insert(static_cast<std::string::size_type>(0), 1, '-'); | |
938 | else | |
939 | e.insert(static_cast<std::string::size_type>(0), 1, '+'); | |
940 | str.append(e); | |
941 | } | |
942 | if(neg) | |
943 | str.insert(static_cast<std::string::size_type>(0), 1, '-'); | |
944 | else if(showpos) | |
945 | str.insert(static_cast<std::string::size_type>(0), 1, '+'); | |
946 | } | |
947 | ||
948 | template <class V> | |
949 | void check_shift_range(V val, const mpl::true_&, const mpl::true_&) | |
950 | { | |
951 | if(val > (std::numeric_limits<std::size_t>::max)()) | |
952 | BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max().")); | |
953 | if(val < 0) | |
954 | BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value.")); | |
955 | } | |
956 | template <class V> | |
957 | void check_shift_range(V val, const mpl::false_&, const mpl::true_&) | |
958 | { | |
959 | if(val < 0) | |
960 | BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value.")); | |
961 | } | |
962 | template <class V> | |
963 | void check_shift_range(V val, const mpl::true_&, const mpl::false_&) | |
964 | { | |
965 | if(val > (std::numeric_limits<std::size_t>::max)()) | |
966 | BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max().")); | |
967 | } | |
968 | template <class V> | |
969 | void check_shift_range(V, const mpl::false_&, const mpl::false_&) BOOST_NOEXCEPT{} | |
970 | ||
971 | } // namespace detail | |
972 | ||
973 | // | |
974 | // Traits class, lets us know what kind of number we have, defaults to a floating point type: | |
975 | // | |
976 | enum number_category_type | |
977 | { | |
978 | number_kind_unknown = -1, | |
979 | number_kind_integer = 0, | |
980 | number_kind_floating_point = 1, | |
981 | number_kind_rational = 2, | |
982 | number_kind_fixed_point = 3 | |
983 | }; | |
984 | ||
985 | template <class Num> | |
986 | struct number_category : public mpl::int_<std::numeric_limits<Num>::is_integer ? number_kind_integer : (std::numeric_limits<Num>::max_exponent ? number_kind_floating_point : number_kind_unknown)> {}; | |
987 | template <class Backend, expression_template_option ExpressionTemplates> | |
988 | struct number_category<number<Backend, ExpressionTemplates> > : public number_category<Backend>{}; | |
989 | template <class tag, class A1, class A2, class A3, class A4> | |
990 | struct number_category<detail::expression<tag, A1, A2, A3, A4> > : public number_category<typename detail::expression<tag, A1, A2, A3, A4>::result_type>{}; | |
991 | ||
992 | template <class T> | |
993 | struct component_type; | |
994 | template <class T, expression_template_option ExpressionTemplates> | |
995 | struct component_type<number<T, ExpressionTemplates> > : public component_type<T>{}; | |
996 | template <class tag, class A1, class A2, class A3, class A4> | |
997 | struct component_type<detail::expression<tag, A1, A2, A3, A4> > : public component_type<typename detail::expression<tag, A1, A2, A3, A4>::result_type>{}; | |
998 | ||
999 | template <class T> | |
1000 | struct is_unsigned_number : public mpl::false_{}; | |
1001 | template <class Backend, expression_template_option ExpressionTemplates> | |
1002 | struct is_unsigned_number<number<Backend, ExpressionTemplates> > : public is_unsigned_number<Backend> {}; | |
1003 | template <class T> | |
1004 | struct is_signed_number : public mpl::bool_<!is_unsigned_number<T>::value> {}; | |
1005 | template <class T> | |
1006 | struct is_interval_number : public mpl::false_ {}; | |
1007 | template <class Backend, expression_template_option ExpressionTemplates> | |
1008 | struct is_interval_number<number<Backend, ExpressionTemplates> > : public is_interval_number<Backend>{}; | |
1009 | ||
1010 | }} // namespaces | |
1011 | ||
1012 | namespace boost{ namespace math{ namespace tools{ | |
1013 | ||
1014 | template <class T> | |
1015 | struct promote_arg; | |
1016 | ||
1017 | template <class tag, class A1, class A2, class A3, class A4> | |
1018 | struct promote_arg<boost::multiprecision::detail::expression<tag, A1, A2, A3, A4> > | |
1019 | { | |
1020 | typedef typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type type; | |
1021 | }; | |
1022 | ||
1023 | template <class R, class B, boost::multiprecision::expression_template_option ET> | |
1024 | inline R real_cast(const boost::multiprecision::number<B, ET>& val) | |
1025 | { | |
1026 | return val.template convert_to<R>(); | |
1027 | } | |
1028 | ||
1029 | template <class R, class tag, class A1, class A2, class A3, class A4> | |
1030 | inline R real_cast(const boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>& val) | |
1031 | { | |
1032 | typedef typename boost::multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type val_type; | |
1033 | return val_type(val).template convert_to<R>(); | |
1034 | } | |
1035 | ||
1036 | ||
1037 | } | |
1038 | ||
1039 | namespace constants{ | |
1040 | ||
1041 | template <class T> | |
1042 | struct is_explicitly_convertible_from_string; | |
1043 | ||
1044 | template <class B, boost::multiprecision::expression_template_option ET> | |
1045 | struct is_explicitly_convertible_from_string<boost::multiprecision::number<B, ET> > | |
1046 | { | |
1047 | static const bool value = true; | |
1048 | }; | |
1049 | ||
1050 | } | |
1051 | ||
1052 | }} | |
1053 | ||
1054 | #ifdef BOOST_MSVC | |
1055 | # pragma warning(pop) | |
1056 | #endif | |
1057 | ||
1058 | #endif // BOOST_MATH_BIG_NUM_BASE_HPP | |
1059 | ||
1060 |