Мне сложно определить, какая реализация 32-битного изменения Fletcher checksum algorithm верна. Википедия предоставляет следующую оптимизированную реализацию:Правильность алгоритма контрольной суммы Fletcher32
uint32_t fletcher32(uint16_t const *data, size_t words) {
uint32_t sum1 = 0xffff, sum2 = 0xffff;
size_t tlen;
while (words) {
tlen = words >= 359 ? 359 : words;
words -= tlen;
do {
sum2 += sum1 += *data++;
} while (--tlen);
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
}
/* Second reduction step to reduce sums to 16 bits */
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
return sum2 << 16 | sum1;
}
Кроме того, я адаптированный неоптимизированный 16-битный пример из статьи Википедии, чтобы вычислить 32-битную контрольные:
uint32_t naive_fletcher32(uint16_t *data, int words) {
uint32_t sum1 = 0;
uint32_t sum2 = 0;
int index;
for(index = 0; index < words; ++index) {
sum1 = (sum1 + data[index]) % 0xffff;
sum2 = (sum2 + sum1) % 0xffff;
}
return (sum2 << 16) | sum1;
}
Оба эти реализации дают одинаковые результаты, например 0x56502d2a
для строки abcdef
. Для того, чтобы убедиться, что это действительно правильно, я попытался найти другие реализации алгоритма:
- An online checksum/hash generator
- C++ implementation in the srecord project
- There's also a JavaScript implementation
Все они, похоже, согласны, что контрольная сумма для abcdef
0x8180255
вместо значения, данного реализацией в Википедии. Я сузил это до того, как работает буфер данных, на котором выполняется реализация. Во всех вышеупомянутых реализациях, отличных от wikipedia, действует один байт за раз, тогда как реализация Wikipedia вычисляет контрольную сумму с использованием 16-битных слов. Если бы я изменить выше «наивную» реализацию Википедии для работы в байтах вместо этого, он читает так:
uint32_t naive_fletcher32_per_byte(uint8_t *data, int words) {
uint32_t sum1 = 0;
uint32_t sum2 = 0;
int index;
for(index = 0; index < words; ++index) {
sum1 = (sum1 + data[index]) % 0xffff;
sum2 = (sum2 + sum1) % 0xffff;
}
return (sum2 << 16) | sum1;
}
Единственное, что меняется, так это подпись, на самом деле. Таким образом, эта измененная наивная реализация и вышеупомянутые реализации (кроме Википедии) согласны с тем, что контрольная сумма abcdef
действительно равна 0x8180255
.
Моя проблема сейчас: какой из них правильный?
В 'naive_fletcher' это'% 0xffff' в цикле не нужны. Вы можете сделать это после цикла. –
Вот почему его наивная реализация, я полагаю: D Спасибо за подсказку, но вопрос не в том, что касается оптимизации :) – fresskoma
@PaulOgilvie: '% 0xffff в цикле не нужны' * до тех пор, пока нет переполнения * , – greybeard