Статья на хабре: Простой и эффективный расчёт Modbus CRC16 в ПЛК и МК без побитового сдвига и таблиц
Я добавил в комментариях к статье реализацию на c# для полинома 0xA001, который используется в Modbus.
Тема на форуме dxdy: Ещё один способ расчёта CRC16
Там я добавил исходник на c# для полинома 0x1021. Для него алгоритм расчёта немного отличается. Есть небольшие комментарии с описанием как это работает.
Думается, что здесь более подходящее место для этой темы.
Без таблицы, без сдвигов (для 0x1021, c#):
public static byte[] Crc16( byte[] bytes )
{
int hi = 0xFF, lo = 0xFF;
foreach ( var b in bytes )
{
var t = ( byte ) ( lo ^ b );
lo = hi;
hi = t;
if ( ( hi & 0x80 ) != 0 ) { hi ^= 0x08; lo ^= 0x10; }
if ( ( hi & 0x40 ) != 0 ) { hi ^= 0x04; lo ^= 0x08; }
if ( ( hi & 0x20 ) != 0 ) { hi ^= 0x02; lo ^= 0x04; }
if ( ( hi & 0x10 ) != 0 ) { hi ^= 0x01; lo ^= 0x02; }
if ( ( hi & 0x08 ) != 0 ) { hi ^= 0x00; lo ^= 0x81; }
if ( ( hi & 0x04 ) != 0 ) { hi ^= 0x80; lo ^= 0x40; }
if ( ( hi & 0x02 ) != 0 ) { hi ^= 0x40; lo ^= 0x20; }
if ( ( hi & 0x01 ) != 0 ) { hi ^= 0x20; lo ^= 0x10; }
}
return new [] { ( byte ) lo, ( byte ) hi };
}