Я борюсь с пониманием алгоритма CRC.Я читал этот учебник , и если я понял его правильно, значение CRC является просто остатком от деления, где сообщение служит дивидендом, а делитель - это заранее заданное значение - выполняется в особом видеполиномиальная арифметика.Это выглядело просто, поэтому я попытался реализовать CRC-32:
public static uint Crc32Naive(byte[] bytes)
{
uint poly = 0x04c11db7; // (Poly)
uint crc = 0xffffffff; // (Init)
foreach (var it in bytes)
{
var b = (uint)it;
for (var i = 0; i < 8; ++i)
{
var prevcrc = crc;
// load LSB from current byte into LSB of crc (RefIn)
crc = (crc << 1) | (b & 1);
b >>= 1;
// subtract polynomial if we've just popped out 1
if ((prevcrc & 0x80000000) != 0)
crc ^= poly;
}
}
return Reverse(crc ^ 0xffffffff); // (XorOut) (RefOut)
}
(где функция Reverese
меняет порядок бит)
Предполагается, что он аналогичен следующему методу деления (снекоторые дополнительные настройки):
1100001010
_______________
10011 ) 11010110110000
10011,,.,,....
-----,,.,,....
10011,.,,....
10011,.,,....
-----,.,,....
00001.,,....
00000.,,....
-----.,,....
00010,,....
00000,,....
-----,,....
00101,....
00000,....
-----,....
01011....
00000....
-----....
10110...
10011...
-----...
01010..
00000..
-----..
10100.
10011.
-----.
01110
00000
-----
1110 = Remainder
Для: 0x00
функция возвращает 0xd202ef8d
, что правильно, но для 0x01
- 0xd302ef8d
вместо 0xa505df1b
(я использовал эта страница , чтобы проверить мои результаты).
Решение из моей реализации имеет для меня больше смысла: увеличение дивиденда на 1 должно изменить напоминание только на 1, верно?Но оказывается, что результат должен выглядеть совершенно иначе.Видимо, я упускаю что-то очевидное.Что это?Как изменение наименее значимого числа в дивиденде может так сильно повлиять на результат?