2012-01-19 37 views
2

這個轉換是否正確嗎?Fletcher校驗和從32bit重新編碼爲8

uint8_t fletcher8(uint8_t *data, uint8_t len) 
{ 
    uint8_t sum1 = 0xff, sum2 = 0xff; 

    while (len) { 
      unsigned tlen = len > 360 ? 360 : len; 
      len -= tlen; 
      do { 
        sum1 += *data++; 
        sum2 += sum1; 
        tlen -= sizeof(uint8_t); 
      } while (tlen); 
      sum1 = (sum1 & 0xff) + (sum1 >> 4); 
      sum2 = (sum2 & 0xff) + (sum2 >> 4); 
    } 
    /* Second reduction step to reduce sums to 4 bits */ 
    sum1 = (sum1 & 0xff) + (sum1 >> 4); 
    sum2 = (sum2 & 0xff) + (sum2 >> 4); 
    return sum2 << 4 | sum1; 
    } 

原文:

uint32_t fletcher32(uint16_t *data, size_t len) 
{ 
    uint32_t sum1 = 0xffff, sum2 = 0xffff; 

    while (len) { 
      unsigned tlen = len > 360 ? 360 : len; 
      len -= tlen; 
      do { 
        sum1 += *data++; 
        sum2 += sum1; 
        tlen -= sizeof(uint16_t); 
      } 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; 
    } 

LEN將是8

數據將數據的[]輸入(1 - 8)

其實我也不知道是什麼處理該行:unsigned tlen = len> 360? 360:len;

也許 - > int8_t tlen = len> 255? 255:len;

+0

您的代碼似乎來自維基百科。您至少應該明確此來源,因爲該材料受[CC-BY-SA許可證](http://en.wikipedia.org/wiki/Wikipedia:CC-BY-SA)的約束。您必須將代碼歸因於其作者。 – MvG

回答

1

我認爲你需要0xF掩碼,而不是0xFF。 32位的使用16位掩碼,32一半,您的8位使用一個8位掩碼,其不是8,4比特的一半是8

uint8_t fletcher8(uint8_t *data, uint8_t len) 
{ 
    uint8_t sum1 = 0xf, sum2 = 0xf; 

    while (len) { 
     unsigned tlen = len > 360 ? 360 : len; 
     len -= tlen; 
     do { 
       sum1 += *data++; 
       sum2 += sum1; 
       tlen -= sizeof(uint8_t); 
     } while (tlen); 
     sum1 = (sum1 & 0xf) + (sum1 >> 4); 
     sum2 = (sum2 & 0xf) + (sum2 >> 4); 
    } 
    /* Second reduction step to reduce sums to 4 bits */ 
    sum1 = (sum1 & 0xf) + (sum1 >> 4); 
    sum2 = (sum2 & 0xf) + (sum2 >> 4); 
    return sum2 << 4 | sum1; 
} 

否則要創建一個不同的校驗一半,不是弗萊徹。例如sum1正在執行我認爲稱爲補碼校驗和的操作。基本上它是先前的16位和你的情況的4位,校驗和是將進位位加回去的地方。在互聯網協議中使用它可以非常容易地修改數據包,而無需計算整個數據包的校驗和,你可以只對現有校驗和進行相加和相減。

附加簡化步驟適用於拐角情況,如果sum1 + = * data = 0x1F使用四位方案的結果,則進位位的添加爲0x01 + 0x0F = 0x10,您需要添加將位回送入以及在循環外0x01 + 0x00 = 0x01。否則,循環和以外的值將加上零。取決於你的體系結構,你可以用類似if(sum1 & 0x10)sum1 = 0x01;比那些可能需要更多指示的瑣碎增加的東西。

當它們變成不僅僅是一個校驗和而且加入了進位的時候,就是兩者結合的最後一步。例如,如果僅使用32位fletcher作爲16位校驗和,那麼您浪費了時間,結果的低16位僅僅是一個進位返回的庫存校驗和,沒有什麼特別的。 sum2是有趣的數字,因爲它是sum1校驗和的累加(sum1是數據的累加,sum2是校驗和的累加)。

+0

很好的答案,謝謝。是的,我使用這個fletcher作爲校驗和;) – Christian

+0

你的代碼仍然使用'tlen'變量的計算,這是[不正確](http://stackoverflow.com/a/13498354/1468366)。由於OP明確表達了對這條線的擔憂,您可能已經提到了您沒有解決這些問題的事實。 – MvG

0

在原始版本sum1中,sum2是32位的。這就是爲什麼事後轉移的原因。在你的情況下,你聲明sum1,sum2是8位,所以位移是沒有意義的。

2

如何計算這個tlen

其實我也不知道該怎麼行辦:無符號TLEN = LEN> 360? 360:len;

該行似乎來自an old versionthis Wikipedia section。到現在爲止已經變成了359,理由解釋在talk page。數僅適用於求和16個實體,它是最大的數Ñ滿足

ÑÑ 5)/ 2×(2 -1)

換句話說,這是次拉爾數目可以添加塊不進行模歸約,並且仍然避免溢出uint32_t。對於4個數據字和一個8位累加器,相應的值將是4,計算使用

ÑÑ 5)/ 2×(2 4 -1

因此,如果您更改了數據大小,則必須修改該行。您也可以更改代碼以使用更大的數據類型來保留其總和,從而在減少之前累計更多的塊。但是在這種情況下,您可能需要在循環內進行多個縮減步驟。

例如,如果你使用uint32_tsum1sum2,那麼你可以溢出的危險之前綜上所述23927所蠶食,但在這之後,你將需要多達7個減排形式sum1 = (sum1 & 0xf) + (sum1 >> 4)的熬下來的範圍10x1e,這是您原始算法的做法。把它寫成(sum1 - 1)%0xf + 1可能更有效率。在這種情況下,您甚至可以將範圍從1到15更改爲0到14,然後將總和初始化爲0並將減少量寫爲sum1 %= 0xf。除非您需要與使用其他範圍的實現兼容。

+1

似乎「對於4位數據字和一個8位累加器,相應值..._」的正確值是** 3 **(不是4)。 –