LCOV - code coverage report
Current view: top level - src/Filters - FixedPoint.hpp (source / functions) Hit Total Coverage
Test: a11a239a890b6a41006679c4a235ba6b91b3e883 Lines: 27 27 100.0 %
Date: 2022-05-08 12:14:49 Functions: 38 38 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <AH/STL/cmath>
       4             : #include <AH/STL/cstdint>
       5             : #include <AH/STL/limits>
       6             : #include <AH/STL/type_traits>
       7             : 
       8             : #include <AH/Error/Error.hpp>
       9             : 
      10             : template <class T>
      11             : struct DoubleWidthInt {
      12             :     using type = void;
      13             : };
      14             : 
      15             : template <>
      16             : struct DoubleWidthInt<uint8_t> {
      17             :     using type = uint16_t;
      18             : };
      19             : 
      20             : template <>
      21             : struct DoubleWidthInt<int8_t> {
      22             :     using type = int16_t;
      23             : };
      24             : 
      25             : template <>
      26             : struct DoubleWidthInt<uint16_t> {
      27             :     using type = uint32_t;
      28             : };
      29             : 
      30             : template <>
      31             : struct DoubleWidthInt<int16_t> {
      32             :     using type = int32_t;
      33             : };
      34             : 
      35             : template <>
      36             : struct DoubleWidthInt<uint32_t> {
      37             :     using type = uint64_t;
      38             : };
      39             : 
      40             : template <>
      41             : struct DoubleWidthInt<int32_t> {
      42             :     using type = int64_t;
      43             : };
      44             : 
      45             : /// @addtogroup FixedPoint
      46             : /// @{
      47             : 
      48             : /// Get the integer type that has twice the number of bits as the given type.
      49             : template <class T>
      50             : using DoubleWidthInt_t = typename DoubleWidthInt<T>::type;
      51             : 
      52             : /**
      53             :  * @brief   Very basic fixed-point integer implementation.
      54             :  * 
      55             :  * @tparam  T 
      56             :  *          The integer type to use.
      57             :  * @tparam  N 
      58             :  *          The number of fractional bits.
      59             :  * @tparam  T2 
      60             :  *          The integer type to use for intermediate values when mutliplying or
      61             :  *          dividing.
      62             :  */
      63             : template <class T, uint8_t N, class T2 = DoubleWidthInt_t<T>>
      64             : class FixedPoint {
      65             :   public:
      66             :     /// Fixed-point representation of the number one.
      67             :     constexpr static T one = 1 << N;
      68             : 
      69             :     /// Default constructor
      70       30399 :     FixedPoint() : val(0) {}
      71             : 
      72             :     /// Initialize U from a numeric value.
      73             :     template <class U>
      74         212 :     FixedPoint(U f) : val(std::llrint(f * one)) {}
      75             : 
      76             :     /// Convert a raw integer representation to fixed point type.
      77       29302 :     static constexpr FixedPoint raw(T t) {
      78       29302 :         FixedPoint res;
      79       29302 :         res.val = t;
      80       29302 :         return res;
      81             :     }
      82             : 
      83             :     /// Addition.
      84       11522 :     FixedPoint operator+(FixedPoint rhs) const {
      85             :         // if (rhs.val > 0 &&
      86             :         //     this->val > std::numeric_limits<T>::max() - rhs.val) {
      87             :         //     ERROR("Integer overflow", 0x0FF0);
      88             :         //     return raw(std::numeric_limits<T>::max());
      89             :         // }
      90             :         // if (rhs.val < 0 &&
      91             :         //     this->val < std::numeric_limits<T>::min() - rhs.val) {
      92             :         //     ERROR("Integer underflow", 0x0FF1);
      93             :         //     return raw(std::numeric_limits<T>::min());
      94             :         // }
      95       11522 :         return raw(static_cast<T>(
      96       11522 :             static_cast<typename std::make_unsigned<T>::type>(this->val) +
      97       11522 :             static_cast<typename std::make_unsigned<T>::type>(rhs.val)));
      98             :     }
      99             : 
     100             :     /// Subtraction.
     101          65 :     FixedPoint operator-(FixedPoint rhs) const {
     102             :         // return raw(this->val - rhs.val);
     103          65 :         return *this + -rhs;
     104             :     }
     105             : 
     106             :     /// Invert.
     107         125 :     FixedPoint operator-() const { return raw(-this->val); }
     108             : 
     109             :     /// Multiplication.
     110       14305 :     FixedPoint operator*(FixedPoint rhs) const {
     111       14305 :         return raw(div_N(T2(this->val) * T2(rhs.val)));
     112             :     }
     113             : 
     114             :     /// Multiplication with normal integer.
     115           2 :     T2 operator*(T2 rhs) const { return div_N(T2(this->val) * T2(rhs)); }
     116             : 
     117             :     /// Division.
     118        2880 :     FixedPoint operator/(FixedPoint rhs) const {
     119        2880 :         if (rhs.val == one)
     120        2848 :             return raw(this->val);
     121          32 :         return raw(T2(this->val) * one / rhs.val);
     122             :     }
     123             : 
     124             :     /// Divide the given integer by @f$ 2^N @f$.
     125       14307 :     static T div_N(T2 val) {
     126             :         static_assert(std::is_unsigned<T2>::value || (-97 * 2) >> 1 == -97,
     127             :                       "Negative signed right shift incorrect");
     128       14307 :         int neg = val < 0 ? 1 : 0;
     129       14307 :         return (val + (1 << (N - 1)) - neg) >> N;
     130             :     }
     131             : 
     132             :     explicit operator long double() const { return (long double)val / one; }
     133         714 :     explicit operator double() const { return (double)val / one; }
     134         224 :     explicit operator float() const { return (float)val / one; }
     135             : 
     136             :   private:
     137             :     T val;
     138             : };
     139             : 
     140             : /// Multiply normal integer with fixed point integer.
     141             : template <class T, uint8_t N, class T2>
     142           1 : T2 operator*(T lhs, FixedPoint<T, N, T2> rhs) {
     143           1 :     return rhs * lhs;
     144             : }
     145             : 
     146             : /// Multiply normal integer with fixed point integer.
     147             : template <class T, uint8_t N, class T2>
     148             : T2 operator*(T2 lhs, FixedPoint<T, N, T2> rhs) {
     149             :     return rhs * lhs;
     150             : }
     151             : 
     152             : #ifndef ARDUINO
     153             : 
     154             : #include <iosfwd>
     155             : 
     156             : /// Printing a fixed-point integer.
     157             : template <class T, class T2, uint8_t N>
     158             : std::ostream &operator<<(std::ostream &os, FixedPoint<T, N, T2> fp) {
     159             :     return os << double(fp);
     160             : }
     161             : 
     162             : #else
     163             : 
     164             : #include <AH/PrintStream/PrintStream.hpp>
     165             : 
     166             : /// Printing a fixed-point integer.
     167             : template <class T, uint8_t N, class T2>
     168             : Print &operator<<(Print &os, FixedPoint<T, N, T2> fp) {
     169             :     return os << double(fp);
     170             : }
     171             : 
     172             : #endif
     173             : 
     174             : /// @}

Generated by: LCOV version 1.15