QFormat.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. ///
  2. /// \file Util/QFormat.hpp
  3. ///
  4. /// Templated fixed point utilities and Q-format conversions.
  5. ///
  6. /// \copyright
  7. /// Copyright (c) 2015-2016 Josh Blum
  8. /// SPDX-License-Identifier: BSL-1.0
  9. ///
  10. #include <Pothos/Config.hpp>
  11. #include <type_traits>
  12. #include <complex>
  13. #include <cmath>
  14. namespace Pothos {
  15. namespace Util {
  16. //! Determine the fundamental data type of T for primitive types.
  17. template <typename T>
  18. struct Fundamental
  19. {
  20. typedef T Type;
  21. };
  22. //! Overload for getting the fundamental type of std::complex<T>
  23. template <typename T>
  24. struct Fundamental<std::complex<T>>
  25. {
  26. typedef T Type;
  27. };
  28. /*!
  29. * Convert from a Q format number.
  30. *
  31. * - Floating point inputs are passed-through without change.
  32. * - Fixed point inputs are down-shifted by the number of fractional bits.
  33. *
  34. * \tparam T the output data type
  35. * \tparam U the input data type
  36. *
  37. * \param in the input number in Q format
  38. * \param n the number of fractional bits
  39. * \return the output number
  40. */
  41. template <typename T, typename U>
  42. T fromQ(const U &in, const int n);
  43. /*!
  44. * Convert from a Q format number.
  45. * The fractional bits default to half of the fixed point integer size.
  46. */
  47. template <typename T, typename U>
  48. T fromQ(const U &in);
  49. /*!
  50. * Convert a floating point number into Q format.
  51. *
  52. * - Floating point outputs are passed-through without change.
  53. * - Fixed point outputs are shifted up by the number of fractional bits.
  54. *
  55. * \tparam T the output data type
  56. * \tparam U the input data type
  57. *
  58. * \param in the input number
  59. * \param n the number of fractional bits
  60. * \return the output number in Q format
  61. */
  62. template <typename T, typename U>
  63. T floatToQ(const U &in, const int n);
  64. /*!
  65. * Convert a floating point number into Q format.
  66. * The fractional bits default to half of the fixed point integer size.
  67. */
  68. template <typename T, typename U>
  69. T floatToQ(const U &in);
  70. namespace Detail {
  71. template <typename T, typename U>
  72. T fromQImpl(const U &in, const int, std::false_type)
  73. {
  74. return T(in);
  75. }
  76. template <typename T, typename U>
  77. T fromQImpl(const U &in, const int n, std::true_type)
  78. {
  79. return T(in >> n);
  80. }
  81. template <typename T, typename U>
  82. T fromQImpl(const std::complex<U> &in, const int, std::false_type)
  83. {
  84. return T(in);
  85. }
  86. template <typename T, typename U>
  87. T fromQImpl(const std::complex<U> &in, const int n, std::true_type)
  88. {
  89. auto real = fromQ<typename T::value_type, U>(in.real(), n);
  90. auto imag = fromQ<typename T::value_type, U>(in.imag(), n);
  91. return T(real, imag);
  92. }
  93. template <typename T, typename U>
  94. T floatToQImpl(const U &in, const int, std::false_type)
  95. {
  96. return T(in);
  97. }
  98. template <typename T, typename U>
  99. T floatToQImpl(const U &in, const int n, std::true_type)
  100. {
  101. return T(std::ldexp(in, n));
  102. }
  103. template <typename T, typename U>
  104. T floatToQImpl(const std::complex<U> &in, const int, std::false_type)
  105. {
  106. return T(in);
  107. }
  108. template <typename T, typename U>
  109. T floatToQImpl(const std::complex<U> &in, const int n, std::true_type)
  110. {
  111. auto real = floatToQ<typename T::value_type, U>(in.real(), n);
  112. auto imag = floatToQ<typename T::value_type, U>(in.imag(), n);
  113. return T(real, imag);
  114. }
  115. static_assert(std::is_same<typename Fundamental<double>::Type, double>::value, "Fundamental of number");
  116. static_assert(std::is_same<typename Fundamental<std::complex<double>>::Type, double>::value, "Fundamental of complex");
  117. } //namespace Detail
  118. } //namespace Util
  119. } //namespace Pothos
  120. template <typename T, typename U>
  121. T Pothos::Util::fromQ(const U &in, const int n)
  122. {
  123. return Pothos::Util::Detail::fromQImpl<T>(in, n, std::is_integral<typename Fundamental<U>::Type>());
  124. }
  125. template <typename T, typename U>
  126. T Pothos::Util::fromQ(const U &in)
  127. {
  128. const int n = sizeof(typename Fundamental<U>::Type)*4;
  129. return Pothos::Util::Detail::fromQImpl<T>(in, n, std::is_integral<typename Fundamental<U>::Type>());
  130. }
  131. template <typename T, typename U>
  132. T Pothos::Util::floatToQ(const U &in, const int n)
  133. {
  134. return Pothos::Util::Detail::floatToQImpl<T>(in, n, std::is_integral<typename Fundamental<T>::Type>());
  135. }
  136. template <typename T, typename U>
  137. T Pothos::Util::floatToQ(const U &in)
  138. {
  139. const int n = sizeof(typename Fundamental<T>::Type)*4;
  140. return Pothos::Util::Detail::floatToQImpl<T>(in, n, std::is_integral<typename Fundamental<T>::Type>());
  141. }