异构元组的快速8位校验和算法

时间:2018-02-20 06:06:04

标签: c hash simd checksum

假设我有三个包含3个异构整数类型(int16_tint32_tint64_t)的三元组,我想为这3个值计算一个8位无符号校验和。假设所有值都在所有有效位上均匀分布,因此我们不能通过在连接它们时截断任何值来作弊。

对于我来说,计算具有相对较低的冲突率和非加密属性的校验和的快速方法是什么?我猜测我可以连接字节并使用Fletcher的校验和或者Pearson散列的变体,但是我所看到的所有实现看起来都过时了,我希望看到如果我可以进一步利用任何SIMD或现代(Skylake)架构的属性。

我也知道MurmurHash,但它没有8位实现。

2 个答案:

答案 0 :(得分:3)

由于您提到所有值均匀分布在所有位上,因此您只需将元组中的任何字节选为8位散列,忽略其余位,即基本上免费。结果是一个完全一致的散列函数,这是最好的(它的碰撞概率为256,这是不可预测输入的下限)。

如果你输入的比特在某种程度上是不均匀的,那么你只需要一个“更好”的哈希函数(绝大多数情况下,实际数据绝不是随机数,但我猜你的情况不同)。

答案 1 :(得分:2)

Modern x86的速度非常快CRC32C (hardware instruction added in SSE4.2)。通过将int32和int16连接到零扩展的int64_t,并使用两个CRC32C指令来累积单个校验和,可能会得到很好的结果。要让编译器为您执行此操作,请使用imintrin.h中的intrinsics:unsigned __int64 _mm_crc32_u64( unsinged __int64 crc, unsigned __int64 data )

根据Agner Fog's instruction tablescrc32在Skylake上每时钟吞吐量为1,周期延迟为3,因此将其提供2x 8字节并获得32位结果应该只需要2 uops / 6周期延迟。首先将uint64_t输入,以便连接uint16和uint32不在关键路径上,即在shift /或第一个crc32之间创建指令级并行。

然后将crc32c水平XOR降低到8位

uint32_t crc = my_object_crc32(&my_object);
crc ^= crc>>16;
crc ^= crc>>8;
crc = (uint8_t)crc;

水平xor将更宽的crc / hash / checksum的位混合成8位值适用于您要使用的任何哈希函数。

或者只是采用CRC32C的低字节。 IDK,如果你将所有4个字节的XORing降低到1,你可以获得多少。再次,对于任何多字节散列函数都是可行的。

您甚至可以只是水平地对输入中的所有字节进行异或。例如使用16字节SSE2加载加载,并屏蔽填充字节,然后将pshufd / pxor降至8字节,pshuflw / pxor降至4字节。  然后另一个pshuflw / pxor减少到2个字节,movd变为整数,用于最终的shift / xor。 (或者你可以提前movd到整数,特别是如果编译器有BMI2 rorx用一条指令进行复制和移位的话。)