C++ 确定在用户输入中存储差异所需的最小字段大小的有效方法

C++ 确定在用户输入中存储差异所需的最小字段大小的有效方法,c++,bit-manipulation,C++,Bit Manipulation,对不起,这个标题太笨拙了;我找不到一点表达我想做什么的方式 我从多个32位整数的用户那里得到一个输入。例如,用户可以输入以下值(以十六进制显示以便于解释): 在这种特殊情况下,每个输入的前2个字节是常量,最后2个字节是变量。为了提高效率,我可以将0x0000存储为单个常量,并创建uint16\t值的向量来存储输入的可变部分(0x1234,0x5678,0xabcd) 现在假设用户输入以下内容: 0x00000234 0x56780000 0x00001000 uint32_t myVal =

对不起,这个标题太笨拙了;我找不到一点表达我想做什么的方式

我从多个32位整数的用户那里得到一个输入。例如,用户可以输入以下值(以十六进制显示以便于解释):

在这种特殊情况下,每个输入的前2个字节是常量,最后2个字节是变量。为了提高效率,我可以将
0x0000
存储为单个常量,并创建
uint16\t
值的向量来存储输入的可变部分(
0x1234
0x5678
0xabcd

现在假设用户输入以下内容:

0x00000234
0x56780000
0x00001000
uint32_t myVal = 0;
myVal |= input1;
myVal |= input2;
// ...
在这种情况下,我需要一个
uint32\u t
值的向量来存储输入的可变部分,因为每个值影响不同的字节


我目前的想法是做以下几点:

0x00000234
0x56780000
0x00001000
uint32_t myVal = 0;
myVal |= input1;
myVal |= input2;
// ...
然后在末尾找到
myVal
中第一个和最后一个“切换”(即
1
)位之间的距离。该距离将为所有输入的可变部分提供所需的字段大小

然而,对于大量的用户输入来说,这听起来并不能很好地扩展。有没有关于一种优雅而有效的方法来确定这一点的建议


更新:

我在上面的解释中简化了这个问题

要清楚的是,我这样做并不是为了节省内存(我有更好的事情要做,而不是试图节省一些字节,这不是为了优化目的)

总之,组件A为我的系统中的组件B提供了值。有时这些值为128位,但组件B仅支持32位值

如果128位值的可变部分可以用32位值表示,我可以接受它。否则,我将需要以错误拒绝它


我不能修改组件B以允许128位值,也不能修改组件a以防止使用128位值(这里也有硬件限制)

虽然我看不出这一切的原因。。。为什么不将输入与std::numeric\u limits::max()进行比较呢?如果输入值较大,则需要使用
uint32\u t


回答您的编辑:

我认为为了获得更好的性能,您应该使用特定于硬件的低级指令。您可以迭代输入128位值的32位部分,然后将每个部分添加到某个变量中,并检查下一个值和当前总和之间的差异。如果差值不等于总和,则应跳过此128位值,否则最终将得到必要的结果。样本如下:

uint32_t get_value( uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4)
{
  uint32_t temp = v1; 
  if ( temp - v2 != temp ) throw exception;
  temp += v2; if ( temp - v3 != temp ) throw exception;
  temp += v3; if ( temp - v4 != temp ) throw exception;
  temp = v4;
  return temp;
}

这个C++示例可能看起来很傻,但是我相信汇编代码应该有效地处理输入流。

< P>在代码< > [0,(2 ^ 32)-1 ] < /code >范围内存储一系列无符号整数的最有效方法是使用<代码> UTI32×T < < /code >。为了从用户输入中节省2个字节而跳槽是不值得的——用户不可能在其有生之年输入足够的整数,以至于代码必须开始压缩它们。在任何现代系统的内存限制变得明显之前,他(她)早就老死了。

看起来你必须想出一个累积的位掩码——然后你可以查看它,看看你是有尾随的还是前导的常量位。需要对每个输入操作的算法(使其成为O(n)算法,其中n是要检查的值的数量)

算法类似于您已经完成的操作:

unsigned long long bitmask = 0uL;
std::size_t count = val.size();
for (std::size_t i = 0; i < count; ++i)
  bitmask |= val[i];
无符号长位掩码=0uL;
std::size_t count=val.size();
对于(std::size\u t i=0;i
然后,您可以检查有多少位/字节前导/尾随可以保持不变,以及是否要使用完整的32位。如果您可以访问SSE指令,则可以使用OpenMP对此进行矢量化

还有一种可能的优化方法是短路,查看第一个
1
位和最后一个
1
位之间的距离是否已经大于32,在这种情况下,您可以停止


为了使这个算法能够更好地扩展,您必须并行地执行它。你的朋友可能是矢量处理(如果你在Mac或已经支持OpenCL的平台上,或者只是OpenMP注释,可能会使用CUDA for Nvidia GPU,或者OpenCL)。

存储遇到的第一个完整的128位数字,然后将其低阶32位推到矢量上,设置
bool reject\u all=false
。对于每个剩余的数字,如果高阶(128-32=96)位与第一个数字不同,则设置
reject\u all=true
,否则将其低阶位推送到向量上。在循环结束时,使用reject_all决定是否使用值向量。

使用

uint32_t ORVal = 0;
uint32_t ANDVal = 0xFFFFFFFF;

ORVal  |= input1;
ANDVal &= input1;
ORVal  |= input2;
ANDVal &= input2;
ORVal  |= input3;
ANDVal &= input3; // etc.

// At end of input...
mask = ORVal ^ ANDVal; 
// bit positions set to 0 were constant, bit positions set to 1 changed
如果至少有一个输入在该位置有
1
,则
ORVal
中的位位置将为
1
,如果所有输入在该位置有
0
,则
0
。如果至少有一个输入在该位位置有
0
,则
ANDVal
中的位位置将为
0
,如果所有输入在该位置有
1
,则
1

如果输入中的位位置始终为
1
,则
ORVal
ANDVal
都将设置为
1
。 如果输入中的位位置始终为
0
,则
ORVal
ANDVal
都将设置为
0

如果位位置混合了
0
1
,那么
ORVal
将被设置为
1
,而
和val
将被设置为
0
,因此末尾的
XOR
给出了更改位位置的掩码。

你为什么觉得需要这样做?@GMan-