promotion.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // boost\math\tools\promotion.hpp
  2. // Copyright John Maddock 2006.
  3. // Copyright Paul A. Bristow 2006.
  4. // Use, modification and distribution are subject to the
  5. // Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. // Promote arguments functions to allow math functions to have arguments
  9. // provided as integer OR real (floating-point, built-in or UDT)
  10. // (called ArithmeticType in functions that use promotion)
  11. // that help to reduce the risk of creating multiple instantiations.
  12. // Allows creation of an inline wrapper that forwards to a foo(RT, RT) function,
  13. // so you never get to instantiate any mixed foo(RT, IT) functions.
  14. #ifndef BOOST_MATH_PROMOTION_HPP
  15. #define BOOST_MATH_PROMOTION_HPP
  16. #ifdef _MSC_VER
  17. #pragma once
  18. #endif
  19. // Boost type traits:
  20. #include <boost/math/tools/config.hpp>
  21. #include <boost/type_traits/is_floating_point.hpp> // for boost::is_floating_point;
  22. #include <boost/type_traits/is_integral.hpp> // for boost::is_integral
  23. #include <boost/type_traits/is_convertible.hpp> // for boost::is_convertible
  24. #include <boost/type_traits/is_same.hpp>// for boost::is_same
  25. #include <boost/type_traits/remove_cv.hpp>// for boost::remove_cv
  26. // Boost Template meta programming:
  27. #include <boost/mpl/if.hpp> // for boost::mpl::if_c.
  28. #include <boost/mpl/and.hpp> // for boost::mpl::if_c.
  29. #include <boost/mpl/or.hpp> // for boost::mpl::if_c.
  30. #include <boost/mpl/not.hpp> // for boost::mpl::if_c.
  31. #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  32. #include <boost/static_assert.hpp>
  33. #endif
  34. namespace boost
  35. {
  36. namespace math
  37. {
  38. namespace tools
  39. {
  40. // If either T1 or T2 is an integer type,
  41. // pretend it was a double (for the purposes of further analysis).
  42. // Then pick the wider of the two floating-point types
  43. // as the actual signature to forward to.
  44. // For example:
  45. // foo(int, short) -> double foo(double, double);
  46. // foo(int, float) -> double foo(double, double);
  47. // Note: NOT float foo(float, float)
  48. // foo(int, double) -> foo(double, double);
  49. // foo(double, float) -> double foo(double, double);
  50. // foo(double, float) -> double foo(double, double);
  51. // foo(any-int-or-float-type, long double) -> foo(long double, long double);
  52. // but ONLY float foo(float, float) is unchanged.
  53. // So the only way to get an entirely float version is to call foo(1.F, 2.F),
  54. // But since most (all?) the math functions convert to double internally,
  55. // probably there would not be the hoped-for gain by using float here.
  56. // This follows the C-compatible conversion rules of pow, etc
  57. // where pow(int, float) is converted to pow(double, double).
  58. template <class T>
  59. struct promote_arg
  60. { // If T is integral type, then promote to double.
  61. typedef typename mpl::if_<is_integral<T>, double, T>::type type;
  62. };
  63. // These full specialisations reduce mpl::if_ usage and speed up
  64. // compilation:
  65. template <> struct promote_arg<float> { typedef float type; };
  66. template <> struct promote_arg<double>{ typedef double type; };
  67. template <> struct promote_arg<long double> { typedef long double type; };
  68. template <> struct promote_arg<int> { typedef double type; };
  69. template <class T1, class T2>
  70. struct promote_args_2
  71. { // Promote, if necessary, & pick the wider of the two floating-point types.
  72. // for both parameter types, if integral promote to double.
  73. typedef typename promote_arg<T1>::type T1P; // T1 perhaps promoted.
  74. typedef typename promote_arg<T2>::type T2P; // T2 perhaps promoted.
  75. typedef typename mpl::if_<
  76. typename mpl::and_<is_floating_point<T1P>, is_floating_point<T2P> >::type, // both T1P and T2P are floating-point?
  77. #ifdef BOOST_MATH_USE_FLOAT128
  78. typename mpl::if_< typename mpl::or_<is_same<__float128, T1P>, is_same<__float128, T2P> >::type, // either long double?
  79. __float128,
  80. #endif
  81. typename mpl::if_< typename mpl::or_<is_same<long double, T1P>, is_same<long double, T2P> >::type, // either long double?
  82. long double, // then result type is long double.
  83. typename mpl::if_< typename mpl::or_<is_same<double, T1P>, is_same<double, T2P> >::type, // either double?
  84. double, // result type is double.
  85. float // else result type is float.
  86. >::type
  87. #ifdef BOOST_MATH_USE_FLOAT128
  88. >::type
  89. #endif
  90. >::type,
  91. // else one or the other is a user-defined type:
  92. typename mpl::if_< typename mpl::and_<mpl::not_<is_floating_point<T2P> >, ::boost::is_convertible<T1P, T2P> >, T2P, T1P>::type>::type type;
  93. }; // promote_arg2
  94. // These full specialisations reduce mpl::if_ usage and speed up
  95. // compilation:
  96. template <> struct promote_args_2<float, float> { typedef float type; };
  97. template <> struct promote_args_2<double, double>{ typedef double type; };
  98. template <> struct promote_args_2<long double, long double> { typedef long double type; };
  99. template <> struct promote_args_2<int, int> { typedef double type; };
  100. template <> struct promote_args_2<int, float> { typedef double type; };
  101. template <> struct promote_args_2<float, int> { typedef double type; };
  102. template <> struct promote_args_2<int, double> { typedef double type; };
  103. template <> struct promote_args_2<double, int> { typedef double type; };
  104. template <> struct promote_args_2<int, long double> { typedef long double type; };
  105. template <> struct promote_args_2<long double, int> { typedef long double type; };
  106. template <> struct promote_args_2<float, double> { typedef double type; };
  107. template <> struct promote_args_2<double, float> { typedef double type; };
  108. template <> struct promote_args_2<float, long double> { typedef long double type; };
  109. template <> struct promote_args_2<long double, float> { typedef long double type; };
  110. template <> struct promote_args_2<double, long double> { typedef long double type; };
  111. template <> struct promote_args_2<long double, double> { typedef long double type; };
  112. template <class T1, class T2=float, class T3=float, class T4=float, class T5=float, class T6=float>
  113. struct promote_args
  114. {
  115. typedef typename promote_args_2<
  116. typename remove_cv<T1>::type,
  117. typename promote_args_2<
  118. typename remove_cv<T2>::type,
  119. typename promote_args_2<
  120. typename remove_cv<T3>::type,
  121. typename promote_args_2<
  122. typename remove_cv<T4>::type,
  123. typename promote_args_2<
  124. typename remove_cv<T5>::type, typename remove_cv<T6>::type
  125. >::type
  126. >::type
  127. >::type
  128. >::type
  129. >::type type;
  130. #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  131. //
  132. // Guard against use of long double if it's not supported:
  133. //
  134. BOOST_STATIC_ASSERT_MSG((0 == ::boost::is_same<type, long double>::value), "Sorry, but this platform does not have sufficient long double support for the special functions to be reliably implemented.");
  135. #endif
  136. };
  137. //
  138. // This struct is the same as above, but has no static assert on long double usage,
  139. // it should be used only on functions that can be implemented for long double
  140. // even when std lib support is missing or broken for that type.
  141. //
  142. template <class T1, class T2=float, class T3=float, class T4=float, class T5=float, class T6=float>
  143. struct promote_args_permissive
  144. {
  145. typedef typename promote_args_2<
  146. typename remove_cv<T1>::type,
  147. typename promote_args_2<
  148. typename remove_cv<T2>::type,
  149. typename promote_args_2<
  150. typename remove_cv<T3>::type,
  151. typename promote_args_2<
  152. typename remove_cv<T4>::type,
  153. typename promote_args_2<
  154. typename remove_cv<T5>::type, typename remove_cv<T6>::type
  155. >::type
  156. >::type
  157. >::type
  158. >::type
  159. >::type type;
  160. };
  161. } // namespace tools
  162. } // namespace math
  163. } // namespace boost
  164. #endif // BOOST_MATH_PROMOTION_HPP