抱歉笨拙的头衔;我找不到一点表达我想要做的事情。
我从多个32位整数的用户那里得到一个输入。例如,用户可以输入以下值(以十六进制显示以便于解释):
0x00001234
0x00005678
0x0000abcd
在这种特殊情况下,每个输入的前2个字节是常量,最后2个字节是可变的。为了提高效率,我可以将0x0000
存储为单个常量,并创建uint16_t
值的向量来存储输入的变量部分(0x1234
,0x5678
,{ {1}})。
现在让我们说用户输入以下内容:
0xabcd
在这种情况下,我需要一个0x00000234
0x56780000
0x00001000
值的向量来存储输入的可变部分,因为每个值都会影响不同的字节。
我目前的想法是做以下事情:
uint32_t
然后在最后找到uint32_t myVal = 0;
myVal |= input1;
myVal |= input2;
// ...
中第一个和最后一个“切换”(即1
)位之间的距离。该距离将为我提供所有输入的可变部分所需的字段大小。
然而,对于大量用户输入而言,这听起来并不适合。有关优雅高效的确定方法的任何建议吗?
更新
我在上面的解释中简化了问题。
为了清楚起见,我不是为了节省内存(我有更好的事情要做,而不是尝试保存几个字节,这不是为了优化目的)。
总之,组件A为我的系统中的组件B提供了值。有时这些值是128位,但组件B仅支持32位值。
如果128位值的可变部分可以用32位值表示,我可以接受它。否则我将需要拒绝它,但错误。
我无法修改组件B以允许128位值,或修改组件A以防止其使用128位值(此处也存在硬件限制)。
答案 0 :(得分:1)
虽然我看不出有什么理由......为什么不将输入与std::numeric_limits<uint16_t>::max()
进行比较?如果输入值较大,则需要使用uint32_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 ++示例中,它可能看起来很傻但我相信汇编代码应该有效地处理输入流。
答案 1 :(得分:1)
存储您遇到的第一个完整的128位数,然后将其低位32位推到矢量上,设置bool reject_all = false
。对于每个剩余的数字,如果高阶(128-32 = 96)位与第一个数字不同,则设置reject_all = true
,否则将它们的低阶位推到矢量上。在循环结束时,使用reject_all来决定是否使用值向量。
答案 2 :(得分:0)
在[0, (2^32)-1]
范围内存储一系列无符号整数的最有效方法是使用uint32_t
。跳过箍从用户输入中保存2个字节是不值得的 - 用户在其生命周期中不可能输入足够的整数,您的代码必须开始压缩它们。在任何现代系统中记忆限制变得明显之前,他或她就会死于老年。
答案 3 :(得分:0)
看起来你必须想出一个累积的位掩码 - 然后你可以查看它是否有尾随或前导常量位。将需要对每个输入进行操作的算法(使其成为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];
然后,您可以检查前导/尾随的位数/字节数是否可以保持不变,以及是否要使用完整的32位。如果您可以访问SSE指令,则可以使用OpenMP对其进行矢量化。
还可以通过短路进行优化,以查看第一个1
位和最后一个1
位之间的距离是否已经大于32,在这种情况下,您可以停止。
要使此算法更好地扩展,您将不得不并行执行此操作。您的朋友将进行矢量处理(如果您使用的是Mac或已支持OpenCL的平台,或仅使用OpenMP注释,则可能使用CUDA代表Nvidia GPU,或使用OpenCL。)
答案 4 :(得分:0)
使用
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
如果至少有一个输入在该位置ORVal
,则1
中的位位置为1
,如果所有输入中都有0
,则0
位置。如果在该位位置中至少有一个输入具有ANDVal
,则0
中的位位置将为0
,如果所有输入在该位置具有1
,则1
位置为1
。
如果输入中的位位置始终为ORVal
,则ANDVal
和1
都将设置为0
。
如果输入中的位位置始终为ORVal
,则ANDVal
和0
都将设置为0
。
如果某个位置混合了1
和ORVal
,则1
将设置为ANDVal
而0
设置为XOR
,因此,最后的{{1}}给出了改变的位位置的掩码。