當前位置:首頁 » 操作系統 » 16種演算法

16種演算法

發布時間: 2023-01-27 15:29:43

㈠ 7172 5696 4948 9273 5247 6479 8359 怎麼算24點

24點游戲題目【7,1,7,2】共有1種演算法1. [﹙7×7﹚-1]÷2 24點游戲題目【5,6,9,6】共有1種演算法1. ﹙9×6﹚-﹙5×6﹚ 24點游戲題目:用4,4,8,9算24點。24點游戲規則:每個數字只用一次,但可以調換順序,只允許加、減、乘、除等四則運算,可以使用括弧改變運算順序。用4,4,8,9算24點,共有8種演算法。[﹙9×4﹚-8]-4﹙9×4﹚-﹙8+4﹚﹙4×9﹚-﹙4+8﹚[﹙4×9﹚-8]-4﹙4×9﹚-﹙8+4﹚﹙9×4﹚-﹙4+8﹚[﹙9×4﹚-4]-8[﹙4×9﹚-4]-824點游戲題目:用2,3,7,9算24點。24點游戲規則:每個數字只用一次,但可以調換順序,只允許加、減、乘、除等四則運算,可以使用括弧改變運算順序。用2,3,7,9算24點,共有26種演算法。[﹙7×3﹚-9]×2﹙3÷2﹚×﹙9+7﹚9+[3×﹙7-2﹚]3×[﹙7+9﹚÷2][﹙9+7﹚÷2]×3﹙7+9﹚÷﹙2÷3﹚[﹙9+7﹚×3]÷2[﹙7+9﹚×3]÷29-[﹙2-7﹚×3][3×﹙9+7﹚]÷2﹙3÷2﹚×﹙7+9﹚﹙9+7﹚×﹙3÷2﹚[3×﹙7-2﹚]+93÷[2÷﹙7+9﹚]3×[﹙9+7﹚÷2][﹙7-2﹚×3]+9[3×﹙7+9﹚]÷22×[﹙7×3﹚-9]2×[﹙3×7﹚-9]﹙7+9﹚×﹙3÷2﹚﹙9+7﹚÷﹙2÷3﹚3÷[2÷﹙9+7﹚][﹙3×7﹚-9]×29-[3×﹙2-7﹚]9+[﹙7-2﹚×3][﹙7+9﹚÷2]×324點游戲題目:用2,4,5,7算24點。24點游戲規則:每個數字只用一次,但可以調換順序,只允許加、減、乘、除等四則運算,可以使用括弧改變運算順序。用2,4,5,7算24點,共有20種演算法。[﹙7+5﹚×4]÷24÷[2÷﹙5+7﹚]﹙5+7﹚×﹙4-2﹚[4×﹙7+5﹚]÷2﹙7+5﹚×﹙4-2﹚﹙4÷2﹚×﹙7+5﹚[4×﹙5+7﹚]÷2﹙5+7﹚÷﹙2÷4﹚﹙4÷2﹚×﹙5+7﹚﹙7+5﹚×﹙4÷2﹚﹙7+5﹚÷﹙2÷4﹚4÷[2÷﹙7+5﹚]4×[﹙5+7﹚÷2]4×[﹙7+5﹚÷2]﹙4-2﹚×﹙5+7﹚[﹙7+5﹚÷2]×4[﹙5+7﹚×4]÷2﹙5+7﹚×﹙4÷2﹚[﹙5+7﹚÷2]×4﹙4-2﹚×﹙7+5﹚24點游戲題目:用4,6,7,9算24點。24點游戲規則:每個數字只用一次,但可以調換順序,只允許加、減、乘、除等四則運算,可以使用括弧改變運算順序。用4,6,7,9算24點,共有16種演算法。[﹙9+7﹚×6]÷46×[﹙7+9﹚÷4]﹙7+9﹚÷﹙4÷6﹚[﹙9+7﹚÷4]×6﹙9+7﹚×﹙6÷4﹚﹙6÷4﹚×﹙9+7﹚[﹙7+9﹚÷4]×6﹙6÷4﹚×﹙7+9﹚6÷[4÷﹙7+9﹚]﹙7+9﹚×﹙6÷4﹚6÷[4÷﹙9+7﹚][6×﹙7+9﹚]÷46×[﹙9+7﹚÷4][﹙7+9﹚×6]÷4﹙9+7﹚÷﹙4÷6﹚[6×﹙9+7﹚]÷424點游戲題目:用3,5,8,9算24點。24點游戲規則:每個數字只用一次,但可以調換順序,只允許加、減、乘、除等四則運算,可以使用括弧改變運算順序。用3,5,8,9算24點,共有18種演算法。5+[﹙3×9﹚-8][9×﹙8-5﹚]-35+[﹙9×3﹚-8]﹙5-8﹚+﹙3×9﹚[﹙8-5﹚×9]-3﹙9×3﹚-﹙8-5﹚﹙9×3﹚+﹙5-8﹚﹙3×9﹚-﹙8-5﹚[﹙3×9﹚+5]-8﹙5-8﹚+﹙9×3﹚[5+﹙3×9﹚]-8[﹙9×3﹚-8]+5﹙3×9﹚+﹙5-8﹚[5+﹙9×3﹚]-8[﹙3×9﹚-8]+55-[8-﹙3×9﹚][﹙9×3﹚+5]-85-[8-﹙9×3﹚]

㈡ 大數據最常用的演算法有哪些

奧地利符號計算研究所(Research Institute for Symbolic Computation,簡稱RISC)的Christoph Koutschan博士在自己的頁面上發布了一篇文章,提到他做了一個調查,參與者大多數是計算機科學家,他請這些科學家投票選出最重要的演算法,以下是這次調查的結果,按照英文名稱字母順序排序。

大數據等最核心的關鍵技術:32個演算法

1、A* 搜索演算法——圖形搜索演算法,從給定起點到給定終點計算出路徑。其中使用了一種啟發式的估算,為每個節點估算通過該節點的最佳路徑,並以之為各個地點排定次序。演算法以得到的次序訪問這些節點。因此,A*搜索演算法是最佳優先搜索的範例。

2、集束搜索(又名定向搜索,Beam Search)——最佳優先搜索演算法的優化。使用啟發式函數評估它檢查的每個節點的能力。不過,集束搜索只能在每個深度中發現最前面的m個最符合條件的節點,m是固定數字——集束的寬度。

3、二分查找(Binary Search)——在線性數組中找特定值的演算法,每個步驟去掉一半不符合要求的數據。

4、分支界定演算法(Branch and Bound)——在多種最優化問題中尋找特定最優化解決方案的演算法,特別是針對離散、組合的最優化。

5、Buchberger演算法——一種數學演算法,可將其視為針對單變數最大公約數求解的歐幾里得演算法和線性系統中高斯消元法的泛化。

6、數據壓縮——採取特定編碼方案,使用更少的位元組數(或是其他信息承載單元)對信息編碼的過程,又叫來源編碼。

7、Diffie-Hellman密鑰交換演算法——一種加密協議,允許雙方在事先不了解對方的情況下,在不安全的通信信道中,共同建立共享密鑰。該密鑰以後可與一個對稱密碼一起,加密後續通訊。

8、Dijkstra演算法——針對沒有負值權重邊的有向圖,計算其中的單一起點最短演算法。

9、離散微分演算法(Discrete differentiation)。

10、動態規劃演算法(Dynamic Programming)——展示互相覆蓋的子問題和最優子架構演算法

11、歐幾里得演算法(Euclidean algorithm)——計算兩個整數的最大公約數。最古老的演算法之一,出現在公元前300前歐幾里得的《幾何原本》。

12、期望-最大演算法(Expectation-maximization algorithm,又名EM-Training)——在統計計算中,期望-最大演算法在概率模型中尋找可能性最大的參數估算值,其中模型依賴於未發現的潛在變數。EM在兩個步驟中交替計算,第一步是計算期望,利用對隱藏變數的現有估計值,計算其最大可能估計值;第二步是最大化,最大化在第一步上求得的最大可能值來計算參數的值。

13、快速傅里葉變換(Fast Fourier transform,FFT)——計算離散的傅里葉變換(DFT)及其反轉。該演算法應用范圍很廣,從數字信號處理到解決偏微分方程,到快速計算大整數乘積。

14、梯度下降(Gradient descent)——一種數學上的最優化演算法。

15、哈希演算法(Hashing)。

16、堆排序(Heaps)。

17、Karatsuba乘法——需要完成上千位整數的乘法的系統中使用,比如計算機代數系統和大數程序庫,如果使用長乘法,速度太慢。該演算法發現於1962年。

18、LLL演算法(Lenstra-Lenstra-Lovasz lattice rection)——以格規約(lattice)基數為輸入,輸出短正交向量基數。LLL演算法在以下公共密鑰加密方法中有大量使用:背包加密系統(knapsack)、有特定設置的RSA加密等等。

19、最大流量演算法(Maximum flow)——該演算法試圖從一個流量網路中找到最大的流。它優勢被定義為找到這樣一個流的值。最大流問題可以看作更復雜的網路流問題的特定情況。最大流與網路中的界面有關,這就是最大流-最小截定理(Max-flow min-cut theorem)。Ford-Fulkerson 能找到一個流網路中的最大流。

20、合並排序(Merge Sort)。

21、牛頓法(Newton』s method)——求非線性方程(組)零點的一種重要的迭代法。

22、Q-learning學習演算法——這是一種通過學習動作值函數(action-value function)完成的強化學習演算法,函數採取在給定狀態的給定動作,並計算出期望的效用價值,在此後遵循固定的策略。Q-leanring的優勢是,在不需要環境模型的情況下,可以對比可採納行動的期望效用。

23、兩次篩法(Quadratic Sieve)——現代整數因子分解演算法,在實踐中,是目前已知第二快的此類演算法(僅次於數域篩法Number Field Sieve)。對於110位以下的十位整數,它仍是最快的,而且都認為它比數域篩法更簡單。

24、RANSAC——是「RANdom SAmple Consensus」的縮寫。該演算法根據一系列觀察得到的數據,數據中包含異常值,估算一個數學模型的參數值。其基本假設是:數據包含非異化值,也就是能夠通過某些模型參數解釋的值,異化值就是那些不符合模型的數據點。

25、RSA——公鑰加密演算法。首個適用於以簽名作為加密的演算法。RSA在電商行業中仍大規模使用,大家也相信它有足夠安全長度的公鑰。

26、Sch?nhage-Strassen演算法——在數學中,Sch?nhage-Strassen演算法是用來完成大整數的乘法的快速漸近演算法。其演算法復雜度為:O(N log(N) log(log(N))),該演算法使用了傅里葉變換。

27、單純型演算法(Simplex Algorithm)——在數學的優化理論中,單純型演算法是常用的技術,用來找到線性規劃問題的數值解。線性規劃問題包括在一組實變數上的一系列線性不等式組,以及一個等待最大化(或最小化)的固定線性函數。

28、奇異值分解(Singular value decomposition,簡稱SVD)——在線性代數中,SVD是重要的實數或復數矩陣的分解方法,在信號處理和統計中有多種應用,比如計算矩陣的偽逆矩陣(以求解最小二乘法問題)、解決超定線性系統(overdetermined linear systems)、矩陣逼近、數值天氣預報等等。

29、求解線性方程組(Solving a system of linear equations)——線性方程組是數學中最古老的問題,它們有很多應用,比如在數字信號處理、線性規劃中的估算和預測、數值分析中的非線性問題逼近等等。求解線性方程組,可以使用高斯—約當消去法(Gauss-Jordan elimination),或是柯列斯基分解( Cholesky decomposition)。

30、Strukturtensor演算法——應用於模式識別領域,為所有像素找出一種計算方法,看看該像素是否處於同質區域( homogenous region),看看它是否屬於邊緣,還是是一個頂點。

31、合並查找演算法(Union-find)——給定一組元素,該演算法常常用來把這些元素分為多個分離的、彼此不重合的組。不相交集(disjoint-set)的數據結構可以跟蹤這樣的切分方法。合並查找演算法可以在此種數據結構上完成兩個有用的操作:

查找:判斷某特定元素屬於哪個組。

合並:聯合或合並兩個組為一個組。

32、維特比演算法(Viterbi algorithm)——尋找隱藏狀態最有可能序列的動態規劃演算法,這種序列被稱為維特比路徑,其結果是一系列可以觀察到的事件,特別是在隱藏的Markov模型中。

以上就是Christoph博士對於最重要的演算法的調查結果。你們熟悉哪些演算法?又有哪些演算法是你們經常使用的?

㈢ 請問多少除以加乘等於16有幾種演算法

32/4+8
=8+8
=16
結果為16

㈣ 二進制.十進制.八進制.十六進制四種演算法之間的互相轉換) .講簡潔.明白

幾種進制的解釋與轉化說明
一)、數制
計算機中採用的是二進制,因為二進制具有運算簡單,易實現且可靠,為邏輯設計提供了有利的途徑、節省設備等優點,為了便於描述,又常用八、十六進製作為二進制的縮寫.
一般計數都採用進位計數,其特點是:
(1)逢N進一,N是每種進位計數製表示一位數所需要的符號數目為基數.
(2)採用位置表示法,處在不同位置的數字所代表的值不同,而在固定位置上單位數字表示的值是確定的,這個固定位上的值稱為權.
在計算機中:D7 D6 D5 D4 D3 D2 D1 D0 只有兩種0和1
8 4 2 1
二)、數制轉換
不同進位計數制之間的轉換原則:不同進位計數制之間的轉換是根據兩個有理數如相等,則兩數的整數和分數部分一定分別相等的原則進行的.也就是說,若轉換前兩數相等,轉換後仍必須相等.
有四進制
十進制:有10個基數:0 9 ,逢十進一
二進制:有2 個基數:0 1 ,逢二進一
八進制:有8個基數:0 7 ,逢八進一
十六進制:有16個基數:0 9,A,B,C,D,E,F (A=10,B=11,C=12,D=13,E=14,F=15) ,逢十六進一
1、數的進位記數法
N=a n-1*p n-1+a n-2*p n-2+…+a2*p2+a1*p1+a0*p0
2、十進制數與P進制數之間的轉換
①十進制轉換成二進制:十進制整數轉換成二進制整數通常採用除2取余法,小數部分乘2取整法.例如,將(30)10轉換成二進制數.
將(30)10轉換成二進制數
2| 30 ….0 ----最右位
2 15 ….1
2 7 ….1
2 3 ….1
1 ….1 ----最左位
∴ (30)10=(11110)2
將(30)10轉換成八、十六進制數
8| 30 ……6 ------最右位
3 ------最左位
∴ (30)10 =(36)8
16| 30 …14(E)----最右位
1 ----最左位
∴ (30)10 =(1E)16
3、將P進制數轉換為十進制數
把一個二進制轉換成十進制採用方法:把這個二進制的最後一位乘上20,倒數第二位乘上21,……,一直到最高位乘上2n,然後將各項乘積相加的結果就它的十進製表達式.
把二進制11110轉換為十進制
(11110)2=1*24+1*23+1*22+1*21+0*20=
=16+8+4+2+0
=(30)10
把一個八進制轉換成十進制採用方法:把這個八進制的最後一位乘上80,倒數第二位乘上81,……,一直到最高位乘上8n,然後將各項乘積相加的結果就它的十進製表達式.
把八進制36轉換為十進制
(36)8=3*81+6*80=24+6=(30)10
把一個十六進制轉換成十進制採用方法:把這個十六進制的最後一位乘上160,倒數第二位乘上161,……,一直到最高位乘上16n,然後將各項乘積相加的結果就它的十進製表達式.
把十六制1E轉換為十進制
(1E)16=1*161+14*160=16+14=(30)10
3、二進制轉換成八進制數
(1)二進制數轉換成八進制數:對於整數,從低位到高位將二進制數的每三位分為一組,若不夠三位時,在高位左面添0,補足三位,然後將每三位二進制數用一位八進制數替換,小數部分從小數點開始,自左向右每三位一組進行轉換即可完成.例如:
將二進制數1101001轉換成八進制數,則
(001 101 001)2
| | |
( 1 5 1)8
( 1101001)2=(151)8
(2)八進制數轉換成二進制數:只要將每位八進制數用三位二進制數替換,即可完成轉換,例如,把八進制數(643.503)8,轉換成二進制數,則
(6 4 3 .5 0 3)8
| | | | | |
(110 100 011 .101 000 011)2
(643.503)8=(110100011.101000011)2
4、二進制與十六進制之間的轉換
(1)二進制數轉換成十六進制數:由於2的4次方=16,所以依照二進制與八進制的轉換方法,將二進制數的每四位用一個十六進制數碼來表示,整數部分以小數點為界點從右往左每四位一組轉換,小數部分從小數點開始自左向右每四位一組進行轉換.
(2)十六進制轉換成二進制數
如將十六進制數轉換成二進制數,只要將每一位十六進制數用四位相應的二進制數表示,即可完成轉換.
例如:將(163.5B)16轉換成二進制數,則
( 1 6 3 .5 B )16
| | | | |
(0001 0110 0011.0101 1011 )2
(163.5B)16=(101100011.01011011)2

㈤ 幾種CRC16演算法

一. CRC16演算法首先在源文件頭文件加入表值:[c] view plain ////////////////////////////////////////////////////////////////////////// // CRC16碼表 static WORD const wCRC16Table[256] = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040}; 然後在文件中加入下列函數:[c] view plain ////////////////////////////////////////////////////////////////////////// // 函數功能: CRC16效驗 // 輸入參數: pDataIn: 數據地址 // iLenIn: 數據長度 // 輸出參數: pCRCOut: 2位元組校驗值 void CCRCDlg::CRC16(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut) { WORD wResult = 0; WORD wTableNo = 0; for(int i = 0; i < iLenIn; i++) { wTableNo = ((wResult & 0xff) ^ (pDataIn[i] & 0xff)); wResult = ((wResult >> 8) & 0xff) ^ wCRC16Table[wTableNo]; } *pCRCOut = wResult; } 二.CRC16(MODBUS)[c] view plain ////////////////////////////////////////////////////////////////////////// // CRC MODBUS 效驗 // 輸入參數: pDataIn: 數據地址 // iLenIn: 數據長度 // 輸出參數: pCRCOut: 2位元組校驗值 void CCRCDlg::CheckCRCModBus(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut) { WORD wHi = 0; WORD wLo = 0; WORD wCRC; wCRC = 0xFFFF; for (int i = 0; i < iLenIn; i++) { wCRC = CalcCRCModBus(*pDataIn, wCRC); pDataIn++; } wHi = wCRC / 256; wLo = wCRC % 256; wCRC = (wHi > 1; wCRCIn = wCRCIn & 0x7fff; if(wCheck == 1) { wCRCIn = wCRCIn ^ 0xa001; } wCRCIn = wCRCIn & 0xffff; } return wCRCIn; } 三.CRC16(CCITT的0XFFFF)[c] view plain ////////////////////////////////////////////////////////////////////////// // 函數功能: CRC16效驗(CCITT的0XFFFF效驗) // 輸入參數: pDataIn: 數據地址 // iLenIn: 數據長度 // 輸出參數: pCRCOut: 2位元組校驗值 void CCRCDlg::CRCCCITT(const CHAR* pDataIn, int iLenIn, WORD* pCRCOut) { WORD wTemp = 0; WORD wCRC = 0xffff; for(int i = 0; i < iLenIn; i++) { for(int j = 0; j < 8; j++) { wTemp = ((pDataIn[i] > 8); wCRC

㈥ 11乘16有幾種演算法

16+16+16+16+16+16+16+16+16+16+16=* 11+11+11+11+11+11*11+11+11+11+11+11+11+11+11+11=* 11※16 16※11

㈦ 4,5,6,12的24點演算法

可以這樣做:

(6+4)*12/5
=10*12/5
=120/5
=24;

其實,這幾個數字,只有這一種組合,其他的方式,都是有這種組合,演變而來的。

㈧ 16乘以24有幾種不同的演算法

16*24=(20-4)(20+4)=20²-4²=400-16=384

16*24=3*8*8*2=6*64=384

其他的演算法都是類似的都要乘積
16*24=(10+6)*24=240+144=384

㈨ 求助大神還有哪些16位冗餘校驗計算方法,試過常見的幾種CRC16都不對

CRC校驗又稱為循環冗餘校驗,是數據通訊中常用的一種校驗演算法。它可以有效的判別出數據在傳輸過程中是否發生了錯誤,從而保障了傳輸的數據可靠性。

CRC校驗有多種方式,如:CRC8、CRC16、CRC32等等。在實際使用中,我們經常使用CRC16校驗。CRC16校驗也有多種,如:1005多項式、1021多項式(CRC-ITU)等。在這里我們不討論CRC演算法是怎樣產生的,而是重點落在幾種演算法的C51程序的優化上。

計算CRC校驗時,最常用的計算方式有三種:查表、計算、查表+計算。一般來說,查表法最快,但是需要較大的空間存放表格;計演算法最慢,但是代碼最簡潔、佔用空間最小;而在既要求速度,空間又比較緊張時常用查表+計演算法。

下面我們分別就這三種方法進行討論和比較。這里以使用廣泛的51單片機為例,分別用查表、計算、查表+計算三種方法計算
1021多項式(CRC-ITU)校驗。原始程序都是在網上或雜志上經常能見到的,相信大家也比較熟悉了,甚至就是正在使用或已經使用過的程序。

編譯平台採用 Keil C51 7.0,使用小內存模式,編譯器默認的優化方式。

常用的查表法程序如下,這是網上經常能夠看到的程序範例。因為篇幅關系,省略了大部分表格的內容。

code unsigned int Crc1021Table[256] = {

0x0000, 0x1021, 0x2042, 0x3063,... 0x1ef0

};

unsigned int crc0(unsigned char *pData, unsigned char nLength)

{

unsigned int CRC16 = 0;

while(nLength>0)

{

CRC16 = (CRC16 << 8 ) ^ Crc1021Table[((CRC16>>8) ^ *pData) & 0xFF];

nLength--;

pData++;

}

return CRC16;

}

編譯後,函數crc0的代碼為68位元組,加上表格佔用的512位元組,一共使用了580個位元組的代碼空間。

下面是常見的計演算法的程序:

unsigned int crc2(unsigned char *ptr,unsigned char count)

{

unsigned int crc =0;

unsigned char i;

while(count-- >0)

{

crc = ( crc^(((unsigned int)*ptr)<<8));

for(i=0;i<8;i++)

{

if(crc&0x8000) crc= ((crc<<1)^0x1021);

else crc <<= 1;

}

ptr++;

}

return crc;

}

下面是常見的一種查表+計算的方法:

unsigned int crc4(unsigned char *ptr, unsigned char len) {

unsigned int crc;

unsigned char da;

code unsigned int crc_ta[16]={ /* CRC余式表 */

0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,

0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,

};

crc=0;

while(len-->0) {

da = ((crc/256))/16; /* 暫存CRC的高四位 */

crc <<=4;
/* CRC右移4位,相當於取CRC的低12位)*/

crc ^= crc_ta[da^(*ptr/16)];
/* CRC的高4位和本位元組的前半位元組相加後查表*/

/*計算CRC,然後加上上一次CRC的余數 */

da = ((crc/256))/16; /* 暫存CRC的高4位 */

crc <<=4;
/* CRC右移4位, 相當於CRC的低12位) */

crc ^= crc_ta[da^(*ptr&0x0f)];/* CRC的高4位和本位元組的後半位元組相加後查表*/

/*計算CRC,然後再加上上一次CRC的余數 */

ptr++;

}

return crc;

}

程序優化策略:上面程序都只是給出了通用演算法,並沒有考慮到51單片機的特點。我們知道,51單片機是8位單片機,使用的變數類型也是8位的。如果在程序中使用8位的變數速度是最快的,比使用16位的變數代碼短、效率高。在上面的程序中都使用了大量整型數類型(16位)的表格和整型數類型的變數,特別是關鍵的變數。如果我們不使用整型類型的表格和變數,而使用位元組類型的表格和變數,就能夠使程序的性能得到優化。基於這種思路,我們將原來整型的表格拆分為兩個位元組型(8位)的表格,即將原來表格的高低位元組分別拆開,每個表格還是256個單元,這樣表格的大小和順序都沒有變;原來使用16位變數計算的地方,改用8位變數計算。

修改後的查表程序如下(省略了表格的內容):

code unsigned char crctableh[256]={

0x00,0x10,0x20,0x30,... 0x0E,0x1E,

};

code unsigned char crctablel[256]={

0x00,0x21,0x42,0x63,... 0xD1,0xF0,

};

unsigned int crc1(unsigned char *buf,unsigned char n)

{

unsigned char t;

union{

unsigned char c[2];

unsigned int x;

}data crc;

crc.x = 0;

while(n !=0)

{

t = crc.c[0]^*buf;

crc.c[0] = crc.c[1]^crctableh[t];

crc.c[1] = crctablel[t];

n--;

buf++;

}

return ( crc.x );

}

表面上看起來,函數crc1比crc0的源代碼還長一些。但是編譯後,函數crc1的目標代碼實際為44個位元組,加上表格佔用的512個位元組,一共使用了556個位元組,比函數crc0反而節約了24個位元組。這兩個函數的運行對比情況見表一。

我們採用和上面相同的優化方法來優化計演算法的程序,優化後的計演算法程序為:

unsigned int crc3(unsigned char *ptr,unsigned char count)

{

data unsigned char i;

union{

unsigned char c[2];

unsigned int x;

}data crc;

crc.x=0;

while(count!=0)

{

crc.c[0] ^= *ptr;

for(i=8;i>0;i--)

{

if(crc.c[0]&0x70)crc.x=(crc.x<<1)&0x1021;

else crc.x=crc.x<<1;

}

ptr++;

count--;

}

return crc.x;

}

編譯後函數crc2的代碼長度為76,函數crc3的代碼長度為68,變化不是太大,但是執行效率是很不一樣的,具體差別見後面的表一。

優化後的查表+計演算法的程序為:

unsigned int crc5(unsigned char *ptr,unsigned char len)

{

code unsigned char crch[16]={ /* CRC余式表 */

0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,

0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,

};

code unsigned char crcl[16]={ /* CRC余式表 */

0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,

0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,

};

union{

unsigned char c[2];

unsigned int x;

}data crc;

unsigned char t;

crc.x =0;

while(len!=0) {

t = (crc.c[0]>>4) ^ (*ptr >>4);

crc.x <<=4;

crc.c[0] ^=crch[t];

crc.c[1] ^=crcl[t];

t = (crc.c[0]>>4) ^ (*ptr & 0x0F);

crc.x <<=4;

crc.c[0] ^=crch[t];

crc.c[1] ^=crcl[t];

ptr++;

len--;

}

return crc.x;

}

優化前後的代碼長度分別為175位元組和146位元組(包括了32位元組的表格空間)。

代碼測試:僅代碼長度變短是不夠的,衡量優化後的程序一個重要的標準是看優化前後兩個函數執行相同的計算量使用的時間,或者說執行的效率是否提高了。如果優化後的函數需要時間少,就說明我們優化後的函數確實提高了效率,否則就是反而降低了程序的效率,優化失敗。我在 Keil C51 下編寫了一個測試程序,在程序中調用了上面的六個函數,共同計算一個長度為200位元組的CRC校驗,並記錄下每個函數使用的時間。測試方法為:使用 Keil C51 的軟體模擬功能(採用帶計時功能的硬體模擬器也可以),在每個函數上加上斷點,記錄下執行到每個斷點的時間,然後前後相減就得出每個函數的執行時間。模擬時使用的單片機型號為AT89C51,晶體頻率為12MHz。

測試文件的源代碼為:

xdata unsigned char buf[200];

unsigned char i;

unsigned int crc;

extern unsigned int crc0(unsigned char *,unsigned char);

extern unsigned int crc1(unsigned char *,unsigned char);

extern unsigned int crc2(unsigned char *,unsigned char);

extern unsigned int crc3(unsigned char *,unsigned char);

extern unsigned int crc4(unsigned char *,unsigned char);

extern unsigned int crc5(unsigned char *,unsigned char);

void main(void)

{

for(i=0;i<200;i++)

buf[i]=i+1;

crc=crc0(buf,200);

crc=crc1(buf,200);

crc=crc2(buf,200);

crc=crc3(buf,200);

crc=crc4(buf,200);

crc=crc5(buf,200);

i=0;

}

測試結果見表一:

函數

代碼長度(位元組)

執行時間(微秒)

提高效率

查表法

Crc0

68+512=580

10626

28%

Crc1

44+512=556

7622

計演算法

Crc2

76

30309

13.6%

Crc3

68

26186

查表+計算

Crc4

175

24229

18.2%

Crc5

146

19822

表一:三種CRC16校驗演算法及其優化的比較

從表中可以看出,優化後的函數執行速度都有了明顯的提高,這說明我們的優化是很有效的。其實優化前後的函數區別並不大,演算法都是完全一樣的,只是個別地方的寫法調整了一下,但是取得的效果是非常明顯的。現在很多人寫單片機的程序,都帶有寫VC或C++的習慣,而沒有考慮到51單片機的特點,從而造成了一些資源的浪費。

這三種計算方法之間的對比也很清楚,查表法使用的時間最短,查表+計算次之,計演算法最長,它們的執行效率比為1:3.4:2.6,代碼效率比為8.1:1:2.1(優化後的函數)。從代碼長度看,查表法因為使用了一個相對較大的表格,所以代碼最長,適合於代碼空間比較充足的情況;計演算法沒有使用任何錶格,所以代碼長度最小,適合於ROM空間比較小的情況。而查表+計演算法從執行速度和代碼長度都是處於中流,是一種很好的折衷方案。

下面是我總結的一些C51編程優化的幾個小技巧和方法:

1. 盡量使用無符號的變數;

2. 盡量使用data與idata寄存器變數;它們之間的效率順序為data>idata>xdata ;

3. 使用最小的變數類型,能使用整型時就不要使用長整型,能使用字元型時就不要使用整型;

4. 多使用局部變數,少使用全局變數、靜態變數,這樣可以充分利用Keil提供的變數覆蓋技術。同時局部變數也要盡量使用寄存器變數;

5. 少使用浮點數。使用浮點數需要連接浮點庫,會增加大約1K的代碼;而且浮點運算的速度是很慢的,沒有特殊情況盡量使用定點數代替浮點數;

6. 沒有必要就不要使用printf等標准輸入輸出函數,它會增加大約3K的代碼。

7. 函數帶有的參數不要太多,多了會影響效率;

8. 注意C51的特點,按照C51的特點編寫程序;

9. 多用幾種方法優化,比較後找出最佳方法;

10. 注意軟體的寫法,有時一個寫法上很小的變化就會有意想不到的效果。因為Keil的優化是與上下文的程序相關的,對於不同的情況產生不同的優化。如果對比一下產生的匯編代碼,就能夠更加容易的找出不合理的代碼,從而有針對性的優化了;

11. 不要過於依賴C51提供的優化功能,能夠自己優化的地方就自己手工優化了,程序不可能完成所有的事情;

12. 不同版本的C51(特別是6.0和7.0的版本與低於6.0的版本相比)產生的優化效果可能會不同,產生的代碼會不完全一樣,需要特別注意;

13. 在循環中比較條件盡量與0作比較(這與51單片機的特點有關,對比一下編譯產生的匯編代碼就明白了),這樣可以減少代碼,加快速度。如:

將while( n > 10 )修改為

while( n != 0 );

14. 在循環中比較中不要直接使用 n-- 或 n++ ,而要分開寫,這樣產生的代碼較小。

如:while( n-- != 0)修改為

while(n != 0)

{

n--;

...//其他代碼

}

15. 盡量不要使用太復雜的表達式,雖然這樣程序簡潔,但是對程序的調試不方便。

只要能充分考慮到所使用的單片機的特點,在加上一些經驗和技巧,就一定可以編寫出高性能的程序來。

熱點內容
java集合循環 發布:2024-04-27 01:17:18 瀏覽:593
解壓喪屍片 發布:2024-04-27 01:02:28 瀏覽:369
編程師加班 發布:2024-04-27 00:49:24 瀏覽:910
lol四川伺服器雲空間 發布:2024-04-27 00:42:08 瀏覽:933
卡宴怎麼看配置 發布:2024-04-27 00:41:08 瀏覽:941
央視影音緩存視頻怎麼下載視頻 發布:2024-04-27 00:25:55 瀏覽:583
手機緩存的視頻怎麼看 發布:2024-04-27 00:11:05 瀏覽:57
shell腳本平方計算公式 發布:2024-04-26 23:29:26 瀏覽:187
比較實惠的雲伺服器 發布:2024-04-26 23:24:57 瀏覽:974
怎麼增加電腦緩存 發布:2024-04-26 23:23:46 瀏覽:451