LCOV - code coverage report
Current view: top level - src/AH/Math - IncreaseBitDepth.hpp (source / functions) Hit Total Coverage
Test: 169c36a3797bc662d84b5726f34a3f37d3c58247 Lines: 21 21 100.0 %
Date: 2024-11-09 15:32:27 Functions: 63 65 96.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <AH/STL/type_traits> // enable_if
       4             : #include <limits.h>           // CHAR_BIT
       5             : #include <stddef.h>           // size_t
       6             : 
       7             : BEGIN_AH_NAMESPACE
       8             : 
       9             : namespace detail {
      10             : 
      11             : template <size_t Bits_out, size_t Bits_in, class T_out, class T_in>
      12             : std::enable_if_t<(Bits_out <= 2 * Bits_in) && (Bits_out > Bits_in), T_out>
      13         101 : increaseBitDepthImpl(T_in in) {
      14         101 :     constexpr size_t leftShift = Bits_out - Bits_in;
      15         101 :     constexpr size_t rightShift = Bits_in - leftShift;
      16         101 :     return (static_cast<T_out>(in) << leftShift) | (in >> rightShift);
      17             : }
      18             : 
      19             : template <size_t Bits_out, size_t Bits_in, class T_out, class T_in>
      20           2 : std::enable_if_t<(Bits_out <= Bits_in), T_out> increaseBitDepthImpl(T_in in) {
      21           2 :     constexpr size_t rightShift = Bits_in - Bits_out;
      22           2 :     return static_cast<T_out>(in >> rightShift);
      23             : }
      24             : 
      25             : template <size_t Bits_out, size_t Bits_in, class T_out, class T_in>
      26             : std::enable_if_t<(Bits_out > 2 * Bits_in), T_out>
      27          38 : increaseBitDepthImpl(T_in in) {
      28          38 :     constexpr size_t leftShift = Bits_out - Bits_in;
      29          30 :     return (static_cast<T_out>(in) << leftShift) |
      30          38 :            increaseBitDepthImpl<leftShift, Bits_in, T_out>(in);
      31             : }
      32             : 
      33             : } // namespace detail
      34             : 
      35             : /// @addtogroup    AH_Math
      36             : /// @{
      37             : 
      38             : /**
      39             :  * @brief   Increase the bit depth of the given value from `Bits_in` bits wide
      40             :  *          to `Bits_out` bits wide, (approximately) evenly distributing the 
      41             :  *          error across the entire range, such that the error for each element
      42             :  *          is between -1 and +1.
      43             :  * 
      44             :  * @see @ref increaseBitDepthMiddle
      45             :  * 
      46             :  * For example, converting 3-bit numbers to 7-bit numbers would result in the
      47             :  * following:
      48             :  * 
      49             :  * | in (dec) | in (bin) | out (bin) | out (dec) | exact  | error |
      50             :  * |:--------:|:--------:|:---------:|:---------:|:------:|:-----:|
      51             :  * | 0        | 000      | 000'0000  | 0         | 0.00   | +0.00 |
      52             :  * | 1        | 001      | 001'0010  | 18        | 18.14  | +0.14 |
      53             :  * | 2        | 010      | 010'0100  | 36        | 36.29  | +0.29 |
      54             :  * | 3        | 011      | 011'0110  | 54        | 54.43  | +0.43 |
      55             :  * | 4        | 100      | 100'1001  | 73        | 72.57  | -0.43 |
      56             :  * | 5        | 101      | 101'1011  | 91        | 90.71  | -0.29 |
      57             :  * | 6        | 110      | 110'1101  | 109       | 108.86 | -0.14 |
      58             :  * | 7        | 111      | 111'1111  | 127       | 127.00 | +0.00 |
      59             :  *
      60             :  * The following is a comparison to the @ref increaseBitDepthMiddle function.
      61             :  *
      62             :  * @image html increase-bit-depth.svg
      63             :  *
      64             :  * @tparam  Bits_out 
      65             :  *          The number of bits of the output range.
      66             :  * @tparam  Bits_in 
      67             :  *          The number of bits of the input range.
      68             :  * @tparam  T_out 
      69             :  *          The type of the output (return type).
      70             :  * @tparam  T_in 
      71             :  *          The type of the input.
      72             :  * @param   in 
      73             :  *          The value to scale up.
      74             :  * @return  The scaled up value.
      75             :  */
      76             : template <size_t Bits_out, size_t Bits_in, class T_out, class T_in>
      77         103 : T_out increaseBitDepth(T_in in) {
      78             :     static_assert(Bits_in <= sizeof(T_in) * CHAR_BIT,
      79             :                   "Error: Bits_in > bits(T_in)");
      80             :     static_assert(Bits_out <= sizeof(T_out) * CHAR_BIT,
      81             :                   "Error: Bits_out > bits(T_out)");
      82         103 :     return detail::increaseBitDepthImpl<Bits_out, Bits_in, T_out>(in);
      83             : }
      84             : 
      85             : /**
      86             :  * @brief   Increase the bit depth of the given value from `Bits_in` bits wide
      87             :  *          to `Bits_out` bits wide, while ensuring that the middle of the input
      88             :  *          range maps exactly to the middle of the output range, i.e.
      89             :  *          @f$ 2^{\texttt{Bits\_in} - 1} @f$ maps to
      90             :  *          @f$ 2^{\texttt{Bits\_out} - 1} @f$.
      91             :  * 
      92             :  * @see @ref increaseBitDepth
      93             :  *
      94             :  * For example, converting 3-bit numbers to 7-bit numbers would result in the
      95             :  * following:
      96             :  * 
      97             :  * | in (dec) | in (bin) | out (bin) | out (dec) | exact  | error |
      98             :  * |:--------:|:--------:|:---------:|:---------:|:------:|:-----:|
      99             :  * | 0        | 000      | 000'0000  | 0         | 0.00   | +0.00 |
     100             :  * | 1        | 001      | 001'0000  | 16        | 18.14  | -2.14 |
     101             :  * | 2        | 010      | 010'0000  | 32        | 36.29  | -4.29 |
     102             :  * | 3        | 011      | 011'0000  | 48        | 54.43  | -6.43 |
     103             :  * | 4        | 100      | 100'0000  | 64        | 72.57  | -8.57 |
     104             :  * | 5        | 101      | 101'0101  | 85        | 90.71  | -5.71 |
     105             :  * | 6        | 110      | 110'1010  | 106       | 108.86 | -2.86 |
     106             :  * | 7        | 111      | 111'1111  | 127       | 127.00 | +0.00 |
     107             :  *
     108             :  * The following is a comparison to the @ref increaseBitDepth function.
     109             :  *
     110             :  * @image html increase-bit-depth.svg
     111             :  * 
     112             :  * @tparam  Bits_out 
     113             :  *          The number of bits of the output range.
     114             :  * @tparam  Bits_in 
     115             :  *          The number of bits of the input range.
     116             :  * @tparam  T_out 
     117             :  *          The type of the output (return type).
     118             :  * @tparam  T_in 
     119             :  *          The type of the input.
     120             :  * @param   in 
     121             :  *          The value to scale up.
     122             :  * @return  The scaled up value.
     123             :  */
     124             : template <size_t Bits_out, size_t Bits_in, class T_out, class T_in>
     125          20 : T_out increaseBitDepthMiddle(T_in in) {
     126             :     static_assert(Bits_in <= sizeof(T_in) * CHAR_BIT,
     127             :                   "Error: Bits_in > bits(T_in)");
     128             :     static_assert(Bits_out <= sizeof(T_out) * CHAR_BIT,
     129             :                   "Error: Bits_out > bits(T_out)");
     130          20 :     constexpr size_t leftShift = Bits_out - Bits_in;
     131          20 :     T_in half = T_in {1} << (Bits_in - 1);
     132          20 :     T_out out = static_cast<T_out>(in) << leftShift;
     133          20 :     if (in > half) {
     134           9 :         T_in repeat = in & (half - 1);
     135           9 :         out |= increaseBitDepth<leftShift, Bits_in - 1, T_out>(repeat);
     136             :     }
     137          20 :     return out;
     138             : }
     139             : 
     140             : /// @}
     141             : 
     142             : END_AH_NAMESPACE

Generated by: LCOV version 1.15