# 2016q3 Homework1 (clz) contributed by <`jayfeng0225`> reviewed by <`kobeyu`> - 輸入的值域並沒有走訪所有的32位元,另外產生測試資料的方式可以更直觀(0x1 << 1) - 由於需要計算clz的時間非常的少,少到可能會測量不出來,所以建議計算時間的loop次數可以再增加(目前是25次) - 建議可以想想各種演算法在位移相同的輸入值所需要的時間比較(ex x=0x01 vs x = 0x80000000連續執行10000次各種演算法所需要的時間比較) - 建議把各種演算法的clz拆分到其他檔案與主程式分離,可思考REUSE的可能 - git commit的內容可以在多描述一些改動的部分 - 關於branch可以參考[git flow](https://ihower.tw/blog/archives/5140)的開發流程 - 看到好的部分是對於演算法的分析蠻詳細的 ## 作業要求 閱讀 [重新理解數值](/s/SkKZBXZT) 裡頭關於 count leading zero ([clz](https://en.wikipedia.org/wiki/Find_first_set#CLZ)) 的描述,設計實驗,比較 32-bit 數值對以下實做的效能差異: * recursive version * iteration version * binary search technique * byte-shift version * Harley's algorithm ## 作業環境 :::info OS : Ubuntu 16.04 LTS CPU : Intel® Core™ i3-2350M @ 2.3GHz Cache : * L1d 快取: 32K * L1i 快取: 32K * L2 快取: 256K * L3 快取: 3072K Mem : 4G ::: ## CLZ的實作 * iteration ver. ```clike= int clz(uint32_t x) { int n = 32, c = 16; do { uint32_t y = x >> c; if (y) { n -= c; x = y; } c >>= 1; } while (c); return (n - x); } ``` * binary search techique ```clike= int clz(uint32_t x) { if (x == 0) return 32; int n = 0; if (x <= 0x0000FFFF) { n += 16; x <<= 16; } if (x <= 0x00FFFFFF) { n += 8; x <<= 8; } if (x <= 0x0FFFFFFF) { n += 4; x <<= 4; } if (x <= 0x3FFFFFFF) { n += 2; x <<= 2; } if (x <= 0x7FFFFFFF) { n += 1; x <<= 1; } return n; } ``` * byte-shift version ```clike= int clz(uint32_t x) { if (x == 0) return 32; int n = 1; if ((x >> 16) == 0) { n += 16; x <<= 16; } if ((x >> 24) == 0) { n += 8; x <<= 8; } if ((x >> 28) == 0) { n += 4; x <<= 4; } if ((x >> 30) == 0) { n += 2; x <<= 2; } n = n - (x >> 31); return n; } ``` 首先驗證基本的三個方法的正確性: ![](https://i.imgur.com/8rgWHx2.png) 接著利用clock_gettime()來紀錄三種方法的執行時間,並且將其繪製成點狀分佈圖。 :::danger 因為電腦設備較舊,要輸出所有整數的執行結果需要花費很多時間,因此目前僅僅列出執行至 200000的結果。 ::: ![](https://i.imgur.com/SFupIQ2.png) --- ## 需要修改的版本 這部份有先參考[作業區](https://hackmd.io/s/H1B7-hGp)其他的同學的結果,所以思考比較快。 ### Recursive ver. :::info __Recursive需要修改的問題為__ 1. 沒有終止條件 2. shift bit與mask需要隨著遞迴改變 * shift bit : 16 -> 8 -> 4 -> 2 -> 1 * mask : 0xFFFF -> 0xFF -> 0xF ::: * 原來的版本 ```clike= uint8_t clz(uint32_t x) { /* shift upper half down, rest is filled up with 0s */ uint16_t upper = (x >> 16); // mask upper half away uint16_t lower = (x & 0xFFFF); return upper ? clz(upper) : 16 + clz(lower); } ``` * 修正後的版本 ```clike= int clz_recursive(uint32_t x,uint32_t shift , uint32_t mask) { if(x == 0) return 32; if(shift == 1) return !(x>>1); /* shift upper half down, rest is filled up with 0s */ uint16_t upper = (x >> shift); // mask upper half away uint16_t lower = (x & mask); uint32_t shift_temp = shift >> 1; return upper ? clz_recursive(upper, shift_temp , mask >> shift_temp) : shift + clz_recursive(lower, shift_temp, mask >> shift_temp ); } ``` * 驗證結果 :::success 驗證結果我使用原來的iteration版本將1~50000的答案輸出到檔案result,並且執行recursive版本輸出到檔案result_recu。最後在使用vimdiff檢查兩者是否有差異,而結果是輸出相同。 ::: ### Harley's algorithm :::info 原來提供的harley algorithm的程式碼是ctz的結果(也就是最後面有幾個0),根據[workfunction筆記](/s/Byyd3nua)內[網站](http://www.hackersdelight.org/hdcodetxt/nlz.c.txt)所提到的,要修改成CLZ的版本需要改變Table的值。 ::: ```clike= #define u 99 static char table[64] = { 32,31, u,16, u,30, 3, u, 15, u, u, u,29, 10, 2, u, u, u,12,14,21, u,19, u, u,28, u,25, u, 9, 1, u, 17, u, 4, u, u, u,11, u, 13,22,20, u,26, u, u,18, 5, u, u,23, u,27, u, 6, u,24, 7, u, 8, u, 0, u }; ``` 其中u代表不會使用到的值,因此將其定義為99 ```clike= uint8_t clz_harley(uint32_t x) { static char table[64] = { 32,31, u,16, u,30, 3, u, 15, u, u, u,29, 10, 2, u, u, u,12,14,21, u,19, u, u,28, u,25, u, 9, 1, u, 17, u, 4, u, u, u,11, u, 13,22,20, u,26, u, u,18, 5, u, u,23, u,27, u, 6, u,24, 7, u, 8, u, 0, u }; /* Propagate leftmost 1-bit to the right */ x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); /* x = x * 0x6EB14F9 */ x = (x << 3) - x; /* Multiply by 7. */ x = (x << 8) - x; /* Multiply by 255. */ x = (x << 8) - x; /* Again. */ x = (x << 8) - x; /* Again. */ return Table[x >> 26]; } ``` * 驗證結果 :::success 驗證結果同樣輸出1~50000的結果,並且儲存在result_har檔案中再使用vimdiff做比較。結果是輸出相同,因此結果也是正確。 ::: ## 時間落點分析圖 ![](https://i.imgur.com/a1taFxF.png) ## 參考資料 * [重新理解數值](/s/SkKZBXZT) * [workfunction筆記](https://hackmd.io/s/Byyd3nua) ###### tags: `jayfeng0225`