打印

10楼:这有点象先有**还是先有蛋的问题。

[复制链接]
19880|32
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lenglx|  楼主 | 2007-6-17 19:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

程序文件请在这里下载https://bbs.21ic.com/upfiles/img/20076/2007619133825985.rar


        CRC(查表)-表的由来
            by lenglx (lenglx@qq.com,lianxi.leng@changhong.com)
                                                    2006/07/25
1)硬件电路组成

    a) x^16 + x^12 + x^5 + 1
     ┌───────────┬─────────────────┬─────────────┐
     ↑  ┌─┬─┬─┬─┐  ↓  ┌─┬─┬─┬─┬─┬─┬─┐  ↓  ┌─┬─┬─┬─┬─┐  │
     ◎←│15│14│13│12│←◎←│11│10│09│08│07│06│05│←◎←│04│03│02│01│00│←┘
     ↑  └─┴─┴─┴─┘      └─┴─┴─┴─┴─┴─┴─┘      └─┴─┴─┴─┴─┘
     in

    b) x^8 + x^2 + x + 1
     ┌───────────────┬─────┬─────┐
     ↑  ┌─┬─┬─┬─┬─┬─┐  ↓  ┌─┐  ↓  ┌─┐  │
     ◎←│07│06│05│04│03│02│←◎←│01│←◎←│00│←┘
     ↑  └─┴─┴─┴─┴─┴─┘      └─┘      └─┘
     in

2) 简单算法模型(按bit计算)
    照以上的硬件电路来看,其工作原理就是:
    如果原来CRC的最高位异或输入是1的话,那么絇OSThttps://bbs.21ic.com/club/bbs/SaveOwnerEd?并且异或生成多项式(图a为0x1021,图b为0x7).
如果原来CRC的最高位异或输入是高位异或输入是0的话,那么结果就是CRC左移一位.

    那么可以得到以下的程序(以图a例)
    U16 crc_cal(bit * in, U32 cnt)
    {
        U16 crc = 0;
        while(cnt--)
        {
            bool tmp = (crc >> 15) ^ *in;
            crc <<= 1;
            if(tmp)
                crc ^= 0x1021;
            in ++;
        }
        return crc;
    }


3) 查表(按字节计算)
    很显然,按比特计算的方法,其效率是低下的.
    下面介绍查表方法(按字节计算).

    要知道为什么可以用查表的方法,需要一些预备知识.

    以图b为例,假设当前的CRC值是1011 1001,现在要输入4比特数据1101,其生成多项式是:0000 0111

    CRC = 1011 1001, in=1101 , G(X)= 0000 0111


                        <计算方法1>                              <计算方法2>
            step:   1011 1001                                   0110 1001

            1:       011 1001 0                                  110 1001 0

            2:        11 1001 00                                  10 1001 00
                    ^ 00 0001 11                                 ^00 0001 11     <1>
                   --------------                               --------------
                      11 1000 11                                  10 1000 11

            3:         1 1000 110                                  0 1000 110
                    ^  0 0000 111                                 ^0 0000 111    <2>
                   ----------------                              -------------
                       1 1000 001                                  0 1000 001

            4:           1000 0010                                   1000 0010


    <计算方法1>是硬件电路的完全模拟算法
    step 1: 将crc左移一位,因为crc的最高位是1,输入也是1,所以不做处理.
    step 2: 将crc左移一位,因为crc的最高位是0,输入是1,所以还需要异或G(X).
    ....
    step 4: 将crc左移一位,因为crc的最高位是0,输入也是0,所以不做处理.
    得到最终的结果 crc = 1000 0010

    实际上,在crc左移以后,是否还要异或生成多项式的条件是: crc的最高位和输入位异或后的值.
    那么是否可以预先将CRC(h)的值与要输入的4比特数据异或,作为是否判断条件呢.

    答案是肯定的. CRC = 1011 1001, in=1101, CRC(h)^in = 0110
    其计算过程见<计算方法2>
    step 1: 将CRC左移一位,因为CRC的最高位是0,所以不做处理.
    step 2: 将CRC左移一位,因为CRC的最高位是1,所以还需要异或G(X).
    ....
    step 4: 将CRC左移一位,因为CRC的最高位是0,所以不做处理.
    得到最终的结果 CRC = 1000 0010


    虽然,上面的结果是一样的,可有证据证明无论什么情况下,结果都是对的?
    静下来想想,你就是知道这2个方法确实能得出相同的结果.
    
    当4比特的输入完成之后,整个CRC值左移了4位,原来的CRC(h)只是作为判断异或生成多项式的条件存在过.
    最终的CRC值完全是G(X)和CRC(l)不停地(异或/移位)的结果.
    虽然,在CRC计算的过程中,CRC不停的在变化着,但:
       1. 如果在<方法1>中,由于CRC的最高位和输入异或后的结果等于0,那么CRC只是左移一位.
          显然2个方法是一样的.
       2. 如果在<方法1>中,由于CRC的最高位和输入异或后的结果等于1,那么CRC左移一位后,还需要异或G(X).
          异或G(X)的过程中,可能使CRC的后续某位产生变化(也可能不变化,视生成多项式的值而定).
           a.如果没发生变化,那当这位最后移到最高位,作为判断条件的时候,仍然是以前的这个值和输入位的异或.
             显然2个计算方法是一样的.
           b.如果变化过, 那当这位最后移到最高位,作为判断条件的时候,是变化过后的值和输入位的异或. 
             但如果<方法1>能引起后续某位的变化,<方法2>同样也会引起同一位的变化.
             这样当这位最后移到最高位,作为判断条件的时候,2种方法的判断条件仍然是一致的.

    * 关于这部分,我描述得不怎么清楚,那是因为我小时候地语文基础没打好,:).
      如果你有更好地描述,请告诉我.
      

    好了,预备知识完毕,现在开始探讨那个查找表是怎么来的.
    请看<方法2>,最终的CRC的结果是: (CRC(l) << 4) ^ <1> ^ <2>
    
          
               <计算方法2> 
               
            CRC = 1011 1001, in=1101 , G(X)= 0000 0111
               |-----------------------> CRC(h)^in =  1011 ^ 1101 = 0110 
               |
               |    |------------------> CRC(l)
              ---- ----                    
              0110 1001     
                        
               110 1001 0           
                                    
                10 1001 00          
               ^00 0001 11     <1>  
              --------------        
                10 1000 11          
                                    
                 0 1000 110         
                ^0 0000 111    <2>  
               -------------        
                 0 1000 001         
                                    
                   1000 0010        
    由于异或的可结合律,其结果等同于: (CRC(l) << 4) ^ ( <1> ^ <2> )  
    这说明, ( <1) ^ <2> )可以预先制作成表格,采用查表的方法计算CRC, 表的索引是 CRC(h) ^ in .
    其结果是: ( CRC(l) << 4) ^ table[ CRC(h) ^ in ].
    因为是4比特,表的大小是16.
    表的内容可以根据G(X),预先计算.
    
    这里举例用的4比特,基于字节的方法可以用同样的方法.
    
    那么现在开始编程了.
    
    U16 crc_tab[256]= {...};
    U16 crc_cal(U8 * ptr, U32 cnt)
    {
        U16 crc = 0;
        U8  da;
        while (cnt--)
        {
            da = crc >> 8;  // CRC(h)
            crc <<= 8;
            crc ^= crc_tab[da ^ *ptr++];
        }
        
        return crc;
    }
    
    既然你已经知道了查表的原理,那么编一个计算表值的程序不成问题了.
    
    #define GX 0x1021
    void CCrcDlg::OnButton1() 
    {
        WORD table[256];
    
        for(int i =0; i<256; i++)
        {
            WORD crc = i << 8;
            for(int n=0; n<8; n++)
            {
                bool tmp = crc & (1<<15) ? true : false;
                crc <<= 1;
                if(tmp)
                    crc ^= GX;
            }
            table  = crc;
        }
    }
    
    那么你得到了这么个表:
    U16 table[256]=
    {
        0X0000, 0X1021, 0X2042, 0X3063, 0X4084, 0X50A5, 0X60C6, 0X70E7, 
        0X8108, 0X9129, 0XA14A, 0XB16B, 0XC18C, 0XD1AD, 0XE1CE, 0XF1EF, 
        0X1231, 0X0210, 0X3273, 0X2252, 0X52B5, 0X4294, 0X72F7, 0X62D6, 
        0X9339, 0X8318, 0XB37B, 0XA35A, 0XD3BD, 0XC39C, 0XF3FF, 0XE3DE, 
        0X2462, 0X3443, 0X0420, 0X1401, 0X64E6, 0X74C7, 0X44A4, 0X5485, 
        0XA56A, 0XB54B, 0X8528, 0X9509, 0XE5EE, 0XF5CF, 0XC5AC, 0XD58D, 
        0X3653, 0X2672, 0X1611, 0X0630, 0X76D7, 0X66F6, 0X5695, 0X46B4, 
        0XB75B, 0XA77A, 0X9719, 0X8738, 0XF7DF, 0XE7FE, 0XD79D, 0XC7BC, 
        0X48C4, 0X58E5, 0X6886, 0X78A7, 0X0840, 0X1861, 0X2802, 0X3823, 
        0XC9CC, 0XD9ED, 0XE98E, 0XF9AF, 0X8948, 0X9969, 0XA90A, 0XB92B, 
        0X5AF5, 0X4AD4, 0X7AB7, 0X6A96, 0X1A71, 0X0A50, 0X3A33, 0X2A12, 
        0XDBFD, 0XCBDC, 0XFBBF, 0XEB9E, 0X9B79, 0X8B58, 0XBB3B, 0XAB1A, 
        0X6CA6, 0X7C87, 0X4CE4, 0X5CC5, 0X2C22, 0X3C03, 0X0C60, 0X1C41, 
        0XEDAE, 0XFD8F, 0XCDEC, 0XDDCD, 0XAD2A, 0XBD0B, 0X8D68, 0X9D49, 
        0X7E97, 0X6EB6, 0X5ED5, 0X4EF4, 0X3E13, 0X2E32, 0X1E51, 0X0E70, 
        0XFF9F, 0XEFBE, 0XDFDD, 0XCFFC, 0XBF1B, 0XAF3A, 0X9F59, 0X8F78, 
        0X9188, 0X81A9, 0XB1CA, 0XA1EB, 0XD10C, 0XC12D, 0XF14E, 0XE16F, 
        0X1080, 0X00A1, 0X30C2, 0X20E3, 0X5004, 0X4025, 0X7046, 0X6067, 
        0X83B9, 0X9398, 0XA3FB, 0XB3DA, 0XC33D, 0XD31C, 0XE37F, 0XF35E, 
        0X02B1, 0X1290, 0X22F3, 0X32D2, 0X4235, 0X5214, 0X6277, 0X7256, 
        0XB5EA, 0XA5CB, 0X95A8, 0X8589, 0XF56E, 0XE54F, 0XD52C, 0XC50D, 
        0X34E2, 0X24C3, 0X14A0, 0X0481, 0X7466, 0X6447, 0X5424, 0X4405, 
        0XA7DB, 0XB7FA, 0X8799, 0X97B8, 0XE75F, 0XF77E, 0XC71D, 0XD73C, 
        0X26D3, 0X36F2, 0X0691, 0X16B0, 0X6657, 0X7676, 0X4615, 0X5634, 
        0XD94C, 0XC96D, 0XF90E, 0XE92F, 0X99C8, 0X89E9, 0XB98A, 0XA9AB, 
        0X5844, 0X4865, 0X7806, 0X6827, 0X18C0, 0X08E1, 0X3882, 0X28A3, 
        0XCB7D, 0XDB5C, 0XEB3F, 0XFB1E, 0X8BF9, 0X9BD8, 0XABBB, 0XBB9A, 
        0X4A75, 0X5A54, 0X6A37, 0X7A16, 0X0AF1, 0X1AD0, 0X2AB3, 0X3A92, 
        0XFD2E, 0XED0F, 0XDD6C, 0XCD4D, 0XBDAA, 0XAD8B, 0X9DE8, 0X8DC9, 
        0X7C26, 0X6C07, 0X5C64, 0X4C45, 0X3CA2, 0X2C83, 0X1CE0, 0X0CC1, 
        0XEF1F, 0XFF3E, 0XCF5D, 0XDF7C, 0XAF9B, 0XBFBA, 0X8FD9, 0X9FF8, 
        0X6E17, 0X7E36, 0X4E55, 0X5E74, 0X2E93, 0X3EB2, 0X0ED1, 0X1EF0 
    }; 
        
---------------------------------- END ------------------------------------

相关帖子

沙发
hotpower| | 2007-6-17 19:52 | 只看该作者

继续~~~

使用特权

评论回复
板凳
mohanwei| | 2007-6-17 19:54 | 只看该作者

不错,看来楼主下了一番功夫了^_^

使用特权

评论回复
地板
HotPower| | 2007-6-18 00:03 | 只看该作者

哈哈~~~俺不知道理论根据,只要菜地里能长即可~~~

使用特权

评论回复
5
平常人| | 2007-6-18 08:15 | 只看该作者

哈哈,菜农碰到农科院的种菜专家了

使用特权

评论回复
6
yewuyi| | 2007-6-18 09:11 | 只看该作者

欢迎连载

使用特权

评论回复
7
HWM| | 2007-6-18 09:25 | 只看该作者

CRC8或CRC16本来就有自身的算法,

所谓查表只不过是将数据事先算好了制成表而已。这样可以更简洁快速,但需要占用一定的空间。

使用特权

评论回复
8
hotpower| | 2007-6-18 23:10 | 只看该作者

对农科院的种菜专家进行的菜污染坚定结果帖图

哈哈~~~不知楼主原来是农科院的种菜专家,菜农这里有礼了~~~


table[1]


table[16]


table[0x18]



哈哈~~~这是菜农4年前做JavaScript菜鸟时的首篇作业~~~

心里真想说要用三角及冗余校验密码技术倒塌世界~~~

可惜那时我还没遇到"发明"倒塌一词的晕友...

使用特权

评论回复
9
高勇| | 2007-6-19 09:32 | 只看该作者

基础知识

基础知识非常需要进一步巩固。欢迎。

使用特权

评论回复
10
古道热肠| | 2007-6-19 11:19 | 只看该作者

楼主的ID让我想到“联想”品牌

   说得不错,尤其是提出的生成CRC表格的方法,从此不必提心吊胆地用网上Down下的那些CRC表格,"我的CRC表我制造","我制造,我放心"

使用特权

评论回复
11
HWM| | 2007-6-19 11:39 | 只看该作者

10楼:这有点象先有**还是先有蛋的问题。

不过在这里可以肯定的是先有算法才会有表。

使用特权

评论回复
12
sklar| | 2007-6-19 12:53 | 只看该作者

呵呵,不知道干什么用的

不要踩我

使用特权

评论回复
13
HotPower| | 2007-6-19 19:13 | 只看该作者

哈哈~~~我几乎不用查表法~~~要CRC64又该如何是好~~~

使用特权

评论回复
14
HotPower| | 2007-6-19 19:18 | 只看该作者

哈哈~~~向农科院士致敬~~~我怎么没想到制个表呢???

哈哈~~~有时间做个"动画"的~~~

使用特权

评论回复
15
lenglx|  楼主 | 2007-6-19 19:54 | 只看该作者

呵呵

64的也同样可以查表啊.

不过实际用途好像不多.

多数的CRC都由硬件做了.

真正用到用软件计算CRC的时候不多.即使用到,也就很常见的2种.

使用特权

评论回复
16
古道热肠| | 2007-6-20 11:34 | 只看该作者

哈哈 ,最近都展绝活

   可喜可贺。

使用特权

评论回复
17
雨夜屠夫| | 2007-6-21 16:06 | 只看该作者

好东西,收藏~

使用特权

评论回复
18
gyt| | 2007-6-23 10:18 | 只看该作者

不错不错

使用特权

评论回复
19
dicat| | 2007-6-25 08:47 | 只看该作者

理解

这个说的很清楚,完全理论计算. 楼主的相当于通俗的理解.
相关链接:https://bbs.21ic.com/upfiles/img/20076/200762584556156.pdf

使用特权

评论回复
20
wimhy| | 2007-6-28 17:29 | 只看该作者

请高手指点一下

    好了,预备知识完毕,现在开始探讨那个查找表是怎么来的.
    请看<方法2>,最终的CRC的结果是: (CRC(l) << 4) ^ <1> ^ <2>
    
          
               <计算方法2> 
               
            CRC = 1011 1001, in=1101 , G(X)= 0000 0111
               |-----------------------> CRC(h)^in =  1011 ^ 1101 = 0110 
               |
               |    |------------------> CRC(l)
              ---- ----                    
              0110 1001     
                        
               110 1001 0           
                                    
                10 1001 00          
               ^00 0001 11     <1>  
              --------------        
                10 1000 11          
                                    
                 0 1000 110         
                ^0 0000 111    <2>  
               -------------        
                 0 1000 001         
                                    
                   1000 0010        
    由于异或的可结合律,其结果等同于: (CRC(l) << 4) ^ ( <1> ^ <2> )  
    这说明, ( <1) ^ <2> )可以预先制作成表格,采用查表的方法计算CRC, 表的索引是 CRC(h) ^ in .
    其结果是: ( CRC(l) << 4) ^ table[ CRC(h) ^ in ].
    因为是4比特,表的大小是16.
    表的内容可以根据G(X),预先计算.
;-------------------------------------------------------------------
这里没有看懂.
最终的CRC的结果是: (CRC(l) << 4) ^ <1> ^ <2>针对这里的计算, <1> ^ <2>在这里的数据是什么呢???



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

186

帖子

1

粉丝