upgrade_val.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
  2. // Copyright 2008-2016 National ICT Australia (NICTA)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ------------------------------------------------------------------------
  15. //! \addtogroup upgrade_val
  16. //! @{
  17. //! upgrade_val is used to ensure an operation such as multiplication is possible between two types.
  18. //! values are upgraded only where necessary.
  19. template<typename T1, typename T2>
  20. struct upgrade_val
  21. {
  22. typedef typename promote_type<T1,T2>::result T1_result;
  23. typedef typename promote_type<T1,T2>::result T2_result;
  24. arma_inline
  25. static
  26. typename promote_type<T1,T2>::result
  27. apply(const T1 x)
  28. {
  29. typedef typename promote_type<T1,T2>::result out_type;
  30. return out_type(x);
  31. }
  32. arma_inline
  33. static
  34. typename promote_type<T1,T2>::result
  35. apply(const T2 x)
  36. {
  37. typedef typename promote_type<T1,T2>::result out_type;
  38. return out_type(x);
  39. }
  40. };
  41. // template<>
  42. template<typename T>
  43. struct upgrade_val<T,T>
  44. {
  45. typedef T T1_result;
  46. typedef T T2_result;
  47. arma_inline static const T& apply(const T& x) { return x; }
  48. };
  49. //! upgrade a type to allow multiplication with a complex type
  50. //! e.g. the int in "int * complex<double>" is upgraded to a double
  51. // template<>
  52. template<typename T, typename T2>
  53. struct upgrade_val< std::complex<T>, T2 >
  54. {
  55. typedef std::complex<T> T1_result;
  56. typedef T T2_result;
  57. arma_inline static const std::complex<T>& apply(const std::complex<T>& x) { return x; }
  58. arma_inline static T apply(const T2 x) { return T(x); }
  59. };
  60. // template<>
  61. template<typename T1, typename T>
  62. struct upgrade_val< T1, std::complex<T> >
  63. {
  64. typedef T T1_result;
  65. typedef std::complex<T> T2_result;
  66. arma_inline static T apply(const T1 x) { return T(x); }
  67. arma_inline static const std::complex<T>& apply(const std::complex<T>& x) { return x; }
  68. };
  69. //! ensure we don't lose precision when multiplying a complex number with a higher precision real number
  70. template<>
  71. struct upgrade_val< std::complex<float>, double >
  72. {
  73. typedef std::complex<double> T1_result;
  74. typedef double T2_result;
  75. arma_inline static const std::complex<double> apply(const std::complex<float>& x) { return std::complex<double>(x); }
  76. arma_inline static double apply(const double x) { return x; }
  77. };
  78. template<>
  79. struct upgrade_val< double, std::complex<float> >
  80. {
  81. typedef double T1_result;
  82. typedef std::complex<float> T2_result;
  83. arma_inline static double apply(const double x) { return x; }
  84. arma_inline static const std::complex<double> apply(const std::complex<float>& x) { return std::complex<double>(x); }
  85. };
  86. //! ensure we don't lose precision when multiplying complex numbers with different underlying types
  87. template<>
  88. struct upgrade_val< std::complex<float>, std::complex<double> >
  89. {
  90. typedef std::complex<double> T1_result;
  91. typedef std::complex<double> T2_result;
  92. arma_inline static const std::complex<double> apply(const std::complex<float>& x) { return std::complex<double>(x); }
  93. arma_inline static const std::complex<double>& apply(const std::complex<double>& x) { return x; }
  94. };
  95. template<>
  96. struct upgrade_val< std::complex<double>, std::complex<float> >
  97. {
  98. typedef std::complex<double> T1_result;
  99. typedef std::complex<double> T2_result;
  100. arma_inline static const std::complex<double>& apply(const std::complex<double>& x) { return x; }
  101. arma_inline static const std::complex<double> apply(const std::complex<float>& x) { return std::complex<double>(x); }
  102. };
  103. //! work around limitations in the complex class (at least as present in gcc 4.1 & 4.3)
  104. template<>
  105. struct upgrade_val< std::complex<double>, float >
  106. {
  107. typedef std::complex<double> T1_result;
  108. typedef double T2_result;
  109. arma_inline static const std::complex<double>& apply(const std::complex<double>& x) { return x; }
  110. arma_inline static double apply(const float x) { return double(x); }
  111. };
  112. template<>
  113. struct upgrade_val< float, std::complex<double> >
  114. {
  115. typedef double T1_result;
  116. typedef std::complex<double> T2_result;
  117. arma_inline static double apply(const float x) { return double(x); }
  118. arma_inline static const std::complex<double>& apply(const std::complex<double>& x) { return x; }
  119. };
  120. //! @}