Возьмите ваш начальный 1024-байтовый блок A и ваш новый 1024-байтовый блок B. Исключительно - или их, чтобы получить блок C. Поскольку вы изменили только четыре байта, C будет набором нулей, четыре байта, которые являются эксклюзивными, -или из предыдущих и новых четырех байтов и еще нескольких нулей.
Теперь вычисляем CRC-16 блока C, но без какой-либо предварительной или последующей обработки.Мы будем называть это CRC-16 '.(Мне нужно было бы увидеть конкретный CRC-16, который вы используете, чтобы увидеть, что это за обработка, если что-нибудь.) Эксклюзивно - или CRC-16 блока A с CRC-16 'блока C, и теперь у вас естьCRC-16 блока B.
На первый взгляд, это может показаться не таким уж большим преимуществом по сравнению с простым вычислением CRC блока B. Однако есть и хитрости для быстрого вычисления CRC группынули.Прежде всего, нули , предшествующие четырем измененным байтам, дают ноль CRC-16 'независимо от того, сколько существует нулей.Таким образом, вы просто начинаете вычислять CRC-16 'с исключительным или из предыдущих и новых четырех байтов.
Теперь вы продолжаете вычислять CRC-16' на оставшихся n нуляхпосле измененных байтов.Обычно для вычисления CRC на n байтов требуется время O ( n ).Однако, если вы знаете, что все они - нули (или все некоторые постоянные значения), то это можно вычислить за время O (log n ).Вы можете увидеть пример того, как это делается в подпрограмме zlib crc32_combine()
, и применить ее к своему CRC.
Учитывая ваши параметры CRC-16 / DNP, подпрограмма zeros()
ниже будет применено запрошенное число нулевых байтов к CRC в O (log n ) времени.
// Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC
// polynomial, reflected. For speed, this requires that a not be zero.
uint16_t multmodp(uint16_t a, uint16_t b) {
uint16_t m = (uint16_t)1 << 15;
uint16_t p = 0;
for (;;) {
if (a & m) {
p ^= b;
if ((a & (m - 1)) == 0)
break;
}
m >>= 1;
b = b & 1 ? (b >> 1) ^ 0xa6bc : b >> 1;
}
return p;
}
// Table of x^2^n modulo p(x).
uint16_t const x2n_table[] = {
0x4000, 0x2000, 0x0800, 0x0080, 0xa6bc, 0x55a7, 0xfc4f, 0x1f78,
0xa31f, 0x78c1, 0xbe76, 0xac8f, 0xb26b, 0x3370, 0xb090
};
// Return x^(n*2^k) modulo p(x).
uint16_t x2nmodp(size_t n, unsigned k) {
k %= 15;
uint16_t p = (uint16_t)1 << 15;
for (;;) {
if (n & 1)
p = multmodp(x2n_table[k], p);
n >>= 1;
if (n == 0)
break;
if (++k == 15)
k = 0;
}
return p;
}
// Apply n zero bytes to crc.
uint16_t zeros(uint16_t crc, size_t n) {
return multmodp(x2nmodp(n, 3), crc);
}