使用查表和乘法可以将时间复杂度降低到 O(1)。解释和示例代码显示在此答案的第三部分。
如果 1000 是一个常数,则为一个由 32 个值组成的预计算表,每个值代表
可以使用 CRC 到 8000 次方 mod poly 的每一位。一组矩阵(每个 CRC 字节一组)可用于一次处理一个字节。两种方法都是恒定时间(固定循环数)O(1)。
如上所述,如果 1000 不是常数,则可以使用平方取幂,这将是 O(log2(n)) 时间复杂度,或者针对某个恒定数量的零位的预先计算表的组合,例如为 256,然后可以使用平方取幂,这样最后一步就是 O(log2(n%256))。
一般优化:对于具有零和非零元素的普通数据,在带有 pclmulqdq(使用 xmm 寄存器)的现代 X86 上,可以实现快速的 crc32(或 crc16),尽管它接近 500 行汇编代码.英特尔文档:crc using pclmulqdq。 github fast crc16 的示例源代码。对于 32 位 CRC,需要一组不同的常数。如果有兴趣,我将源代码转换为使用 Visual Studio ML64.EXE(64 位 MASM),并为左移和右移 32 位 CRC 创建了示例,每个示例都有两组常量,用于两个最流行的 CRC 32 位多项式(左移多边形:crc32:0x104C11DB7 和 crc32c:0x11EDC6F41,右移多边形位反转)。
使用基于软件的无进位乘法模 CRC 多项式快速调整 CRC 的示例代码。这将比使用 32 x 32 矩阵乘法快得多。计算非零数据的 CRC:crf = GenCrc(msg, ...)。为 n 个零字节计算调整常数: pmc = pow(2^(8*n))%poly (使用重复平方的取幂)。然后针对零字节调整CRC:crf = (crf*pmc)%poly。
请注意,时间复杂度可以通过为 i = 1 到 n 生成 pow(2^(8*i))%poly 常量表而降低到 O(1)。然后计算是查表和固定迭代(32个周期)乘以% poly。
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
static uint32_t crctbl[256];
void GenTbl(void) /* generate crc table */
{
uint32_t crc;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++){
crc = c<<24;
for(i = 0; i < 8; i++)
crc = (crc<<1)^((0-(crc>>31))&0x04c11db7);
crctbl[c] = crc;
}
}
uint32_t GenCrc(uint8_t * bfr, size_t size) /* generate crc */
{
uint32_t crc = 0u;
while(size--)
crc = (crc<<8)^crctbl[(crc>>24)^*bfr++];
return(crc);
}
/* carryless multiply modulo crc */
uint32_t MpyModCrc(uint32_t a, uint32_t b) /* (a*b)%crc */
{
uint32_t pd = 0;
uint32_t i;
for(i = 0; i < 32; i++){
pd = (pd<<1)^((0-(pd>>31))&0x04c11db7u);
pd ^= (0-(b>>31))&a;
b <<= 1;
}
return pd;
}
/* exponentiate by repeated squaring modulo crc */
uint32_t PowModCrc(uint32_t p) /* pow(2,p)%crc */
{
uint32_t prd = 0x1u; /* current product */
uint32_t sqr = 0x2u; /* current square */
while(p){
if(p&1)
prd = MpyModCrc(prd, sqr);
sqr = MpyModCrc(sqr, sqr);
p >>= 1;
}
return prd;
}
/* # data bytes */
#define DAT ( 32)
/* # zero bytes */
#define PAD (992)
/* DATA+PAD */
#define CNT (1024)
int main()
{
uint32_t pmc;
uint32_t crc;
uint32_t crf;
uint32_t i;
uint8_t *msg = malloc(CNT);
for(i = 0; i < DAT; i++) /* generate msg */
msg[i] = (uint8_t)rand();
for( ; i < CNT; i++)
msg[i] = 0;
GenTbl(); /* generate crc table */
crc = GenCrc(msg, CNT); /* generate crc normally */
crf = GenCrc(msg, DAT); /* generate crc for data */
pmc = PowModCrc(PAD*8); /* pmc = pow(2,PAD*8)%crc */
crf = MpyModCrc(crf, pmc); /* crf = (crf*pmc)%crc */
printf("%08x %08x\n", crc, crf); /* crf == crc */
free(msg);
return 0;
}