c++ - 将整数类型缩放到不同的位大小
问题描述
如何将整数类型放大/缩小到其他大小,例如从 8 位到 16 位应该是:
- 0x00 -> 0x0000
- 0xFF -> 0xFFFF
到目前为止,这就是我想出的通用解决方案。缩小工作正常,但扩大只有当返回类型的大小是输入类型的两倍时,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 变化,这是我能想到的一种特殊用途。
解决方案
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);
其中to
和from
是各自的位数。
令人惊讶的是,对于8、16、32、64(其中≤ )的from
和的所有可能对,该因子始终是一个整数值。to
from
to
#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
推荐阅读
- amazon-web-services - AWS ec2-user 与普通用户和对 GPU 的访问
- r - 如何使用 geom_count 从最小点中删除笔划?
- javascript - 如何在 React 中隐藏和显示带有 useState 或条件渲染的组件?
- android - 应用程序卸载 Flutter 时不会删除应用程序数据库
- c# - 尝试在 Unity 中创建一个随机 Vector3
- python - 在 Python 中删除 DataFrame 中值的子字符串
- javascript - 将日期发送到views.py后如何更新django模板
- python - 避免for循环使用numpy通过索引值将数组拆分为多个数组
- constants - q/kdb - 在函数内向字典添加新的键值分配时遇到“常量错误”
- python - 如何使用python中的字符串列表在段落中进行精确匹配