首页 > 解决方案 > 将整数类型缩放到不同的位大小

问题描述

如何将整数类型放大/缩小到其他大小,例如从 8 位到 16 位应该是:

到目前为止,这就是我想出的通用解决方案。缩小工作正常,但扩大只有当返回类型的大小是输入类型的两倍时,8 到 16,或 16 到 32,但不是 8 到 32。

我不知道这种函数的其他用途是什么,除了 8 位到 16 位,反之亦然。我只是在修补这个。

#include <iostream>
#include <limits>
#include <type_traits>
#include <math.h>


template<class PxOut, class PxIn,
         typename = typename std::enable_if<std::is_integral<PxOut>::value, PxOut>::type , /// Must be integral
         typename = typename std::enable_if<std::is_integral<PxIn>::value, PxIn>::type,
         typename = typename std::enable_if<!std::is_signed<PxOut>::value, PxOut>::type , /// Must be positive
         typename = typename std::enable_if<!std::is_signed<PxIn>::value, PxOut>::type
         >

static inline constexpr PxOut binScale(PxIn x)
{

    if constexpr ( std::is_same<PxOut,PxIn>::value ){
        return x;
    }

    else if constexpr ( (/*2**/sizeof( PxIn ) ) < sizeof( PxOut ) ){
        /// ## Scale Up
        /// ## https://stackoverflow.com/a/6436100/12209845
        ///
        PxOut xx = PxIn( x );
        const uint8_t sft = sizeof( PxIn ) * 8;
        return ( ( xx + ( xx << sft ) ) << sft ) + std::numeric_limits<PxIn>::max();
    }
    else if constexpr ( sizeof( PxIn ) > sizeof( PxOut ) ){
        /// ## Scale Down
        /// ## https://code.woboq.org/qt5/qtbase/src/gui/painting/qrgba64.h.html#_ZN7QRgba647div_257Et
        ///
        const uint8_t sft = ( sizeof( PxIn ) * 8 ) - sizeof(PxOut) * 8;
        return ( x - ( x >> sft ) ) >> sft;
    }
}
/// Change the types and the test value in the next lines
///
using PxIn = uint8_t;
using PxOut =  uint16_t;
const PxIn dv = 2;


int main(int , char *[])
{
    std::cout << (uint64_t)binScale<PxOut,PxIn>(
                    (std::numeric_limits<PxIn>::max() ) /
                    dv );

    std::cout << std::endl;
    std::cout << (uint64_t)std::numeric_limits<PxOut>::max() / dv ;
    std::cout << std::endl;
    return 0;
}

编辑

应该按照返回类型最大值的百分比来进行缩放。8 位到 16 位,看起来像:

/*
8 bits       :  16 bits
255 -> 65535 :  Scale to 1/1 of 65535 or (0xFFFF)
127 -> 32767 :  Scale to 1/2 of 65535 or (0xFFFF)
85  -> 22015 :  Scale to 1/3 of 65535 or (0xFFFF)
63  -> 16383 :  Scale to 1/4 of 65535 or (0xFFFF)
0   -> 0     :  Scale to 0% of 65535 or (0xFFFF)
*/

假设您有一个 8 位图像,并且您希望将每个像素缩放到 16 位,以便它从 0xFF -> 0xFFFF 变化,这是我能想到的一种特殊用途。

标签: c++c++17

解决方案


OP 尝试执行的一种可能应用是将颜色从较低像素深度(例如每像素 8 位)缩放到较高像素深度(例如每像素 16 位)。

乍一看,您可能认为因子必须是 2 16 / 2 8 = 2 8 = 256,但这是错误的。

它不会将 0xff(8 位白色)映射到 0xff00,其中 16 位白色将是 0xffff。

相反,该因子必须是 0xffff / 0xff = 0x101 = 257。

这是我基于以下示例实现的地方:

using uintN = unsigned long long;

constexpr uintN getMax(uintN nBits)
{
  assert(nBits <= sizeof (uintN) * 8);
  return (uintN)-1 >> (sizeof (uintN) * 8 - nBits);
}

放大系数变为:

uintN f = getMax(to) / getMax(from);

其中tofrom是各自的位数。

令人惊讶的是,对于8、16、32、64(其中≤ )的from和的所有可能对,该因子始终是一个整数值。tofromto

#include <cassert>
#include <iomanip>
#include <iostream>

using uintN = unsigned long long;

constexpr uintN getMax(uintN nBits)
{
  assert(nBits <= sizeof (uintN) * 8);
  return (uintN)-1 >> (sizeof (uintN) * 8 - nBits);
}

int main()
{
  uintN nBits[] = { 8, 16, 32, 64 };
  uintN tests[][3] = {
    { 0x7f, 0x7f7f, 0x7f7f7f7f },
    { 0xab, 0xabab, 0xabababab },
    { 0xff, 0xffff, 0xffffffff }
  };
  for (int i = 0; i < 4; ++i) {
    uintN from = nBits[i];
    for (int j = i + 1; j < 4; ++j) {
      uintN to = nBits[j];
      uintN f = getMax(to) / getMax(from);
      std::cout << std::dec << "from " << from << " bits to " << to << " bits: factor: " << std::hex << f << "\n";
      std::cout << "Samples:\n";
      for (auto test : tests) {
        std::cout << test[i] << " -> " << f * test[i] << '\n';
      }
    }
  }
}

输出:

from 8 bits to 16 bits: factor: 101
Samples:
7f -> 7f7f
ab -> abab
ff -> ffff
from 8 bits to 32 bits: factor: 1010101
Samples:
7f -> 7f7f7f7f
ab -> abababab
ff -> ffffffff
from 8 bits to 64 bits: factor: 101010101010101
Samples:
7f -> 7f7f7f7f7f7f7f7f
ab -> abababababababab
ff -> ffffffffffffffff
from 16 bits to 32 bits: factor: 10001
Samples:
7f7f -> 7f7f7f7f
abab -> abababab
ffff -> ffffffff
from 16 bits to 64 bits: factor: 1000100010001
Samples:
7f7f -> 7f7f7f7f7f7f7f7f
abab -> abababababababab
ffff -> ffffffffffffffff
from 32 bits to 64 bits: factor: 100000001
Samples:
7f7f7f7f -> 7f7f7f7f7f7f7f7f
abababab -> abababababababab
ffffffff -> ffffffffffffffff

coliru 现场演示


推荐阅读