ICS1期中考試複習
//還沒寫完,有需求的還需自學
重點,易錯點,小tip:
對某負數(二補碼)求其真值時,不必傻傻取反加1,等價快速演算法是0xFFFF...-X(該數)+1
取反加一等價於減一取反;結果上看,等價於右側開始所有0不變,直到遇到第一個1(也不變)後,全部取反
注意資料型別的位元組數
有符號數和無符號數運算會被強制轉換成無符號數
區分有符號和無符號,比如char是表示-128~127的,unsigned char就是0~255了。
size_t實際是被typedef成unsigned的,方便整個程式所有對應型別的修改。
1-1-overview
- 前處理器根據以字元#開頭的命令
- 編譯器將hello.i翻譯為彙編語句
- printf函式存在於一個名為printf.o的單獨預編譯好的目標檔案中,這個檔案必須以某種方式與我們的hello.o合併起來
- ./hello執行該程式
- 計算機的主要硬體結構
- 馮諾依曼體系結構
CPU內部由ALU(算術邏輯單元) 、 CU(控制器) 、 暫存器 (PC、IR、PSW、DR、通用暫存器等)、 中斷系統組成
- 阿姆達爾定律
加速比 = 優化之前系統耗時 / 優化後系統耗時
$\frac{1}{(1-P)+\frac{P}{S}}$
其中P是優化部分百分比,S是優化程度(加速效果)
例題
圖形處理器中經常需要的一種轉換是求平方根。浮點(FP)平方根的實現在效能方面有很大差異,特別是在為圖形設計的處理器中,尤為明顯。假設FP平方根(FPSQR)佔用一項關鍵圖形基準測試中20%的執行時間。
有一項提議:升級FPSQR硬體,使這一運算速度提高到原來的10倍。
另一項提議是讓圖形處理器中所有FP指令的執行速度提高到原來的1.6倍,FP指令佔用該應用程式一半的執行時間。
請問兩種方法哪個更好?
$Speedup_{FPSQR}=\frac{1}{(1-0.2)+\frac{0.2}{10}}=1.22$
$Speedup_{FP}=\frac{1}{(1-0.5)+\frac{0.5}{1.6}}=1.23$
所以第二種方法好。
1-2-bits-bops
- bitmap和bloomfilter
關於bloomfilter,參考布隆過濾器,這一篇給你講的明明白白-阿里雲開發者社群 (aliyun.com)
- 不同機型資料型別字長:
對應彙編:byte word dword qword (8 16 32 64 bits)
- 進位制轉換
二進位制數轉換成十進位制數
$(1101.0101)_{2} =(1·2^3 + 1·2^2 + 0·2^1 + 1·2^0 + 0·2^{-1} + 1·2^{-2} + 0·2^{-3} + 1·2^{-4})_{10}=(8+4+0+1+0+0.25+0+0.0625)_{10}=(13.3125)_{10}$
十進位制數轉換成二進位制數
例如:將(57.625)10轉換成二進位制。
整數部分的轉換:
57/2
28/2 餘1 最低位
14/2 餘0
7/2 餘0
3/2 餘1
1/2 餘1
0 餘1 最高位
所以得出: $(57)_{10} = (111001)_{2}$
小數部分的轉換:
0.625
× 2
1.250 整數1 高位
0.250
× 2
0.500 整數0
0.500
× 2
1.000 整數1 低位
所以得出: $(0.625)_{10} = (0.101)_{2}$
總後得出: $(57.625)_{10} = (111001.101)_{2}$
二進位制與十六進位制快速轉換
- 位運算及其性質與常用操作
& | ~ ^ 與 或 非 異或
A^0=A A^1=~A A^A=0
A&0xff=低八位(0xff為mask掩碼)
A^0xff=低八位部分取反
A|0xff=低八位強制置1
例題
DEC公司的VAX計算機:沒有And和Or指令,只有bis和bic指令:Set result z to x and modify it
z = bis (int x, int m) (bit set)
Set result z to 1 at each bit position where m is 1
z = bic(int x, int m) (bit clear)
set result z to 0 at each bit position where m is 1
Use bis and bic to implement
Or(int x, int y)
Xor(int x, int y)
解:bis(x,y)相當於x=x|y;return x;即return x|y;
bic(x,y)相當於x=x&(~y);return x;即return x&(~y)
所以
Void Or (int x, int y) { bis(x, y); }
Void Xor (int x, int y) { bis(bic(x,y), bic(y,x)); }
- 邏輯操作
&& || ! 邏輯與,邏輯或,邏輯非
注意短路效應,可以通過彙編程式碼看懂原因。
邏輯右移高位補0(unsigned)
算數位移高位補符號數(signed如int)
Shift amount < 0 or ≥ word size屬於未定義行為,執行時可能會出現意外。
優先順序問題:1<<2 + 3<<4 means 1<<(2 + 3)<<4
例題
寫出程式碼實現如下函式:
/* Return 1 when x contains an even number of 1s; 0 otherwise.
Assume w=32 */
int even_ones (unsigned x);
你的程式碼最多隻能包括12個算術運算、位運算和邏輯運算。
解
int even_ones (unsigned x) { x=x^(x>>16); x=x^(x>>8); x=x^(x>>4); x=x^(x>>2); x=x^(x>>1); return !(x&1); }
例題
Returns number of 1's a in word
Examples: bitCount(5) = 2, bitCount(7) = 3
Legal ops: ! ~ & ^ | + << >>
Max ops: 40
解
int bitCount(int x) { int m1 = 0x11 | (0x11 << 8); int mask = m1 | (m1 << 16); int s = x & mask; s += x>>1 & mask; s += x>>2 & mask; s += x>>3 & mask; /* Now combine high and low order sums */ s = s + (s >> 16); /* Low order 16 bits now consists of 4 sums. Split into two groups and sum */ mask = 0xF | (0xF << 8); s = (s & mask) + ((s >> 4) & mask); return (s + (s>>8)) & 0x3F; }
1-3-integers
- 資料的表示
關於原碼,反碼,補碼,參考原碼, 反碼, 補碼 詳解 - ziqiu.zhang - 部落格園 (cnblogs.com)(侵刪致歉)
牢記一點,真值是不存在的,是隻存在於數學書上的,機器裡的表示方式只有類似於這三種的編碼規範。
解題時,要求某值的原碼,反碼,補碼,真值轉換。
前三者的互相轉換參見上文,此處討論求真值轉換為補碼(因為現補碼多為機器中真正的儲存方式)
例題
-178轉換成補碼【16進位制short型】
首先由於原碼是人最容易理解的方式,它的缺點是機器計算時帶來的加減法操作差異(這種符號位的存在難以參與運算),但是與我們沒有關係,所以先得到原碼。
所以先寫符號位1,剩下的就是178的二進位制表示,即10110010,所以原碼為1000...010110010
原碼轉補碼十分簡單,非符號位“取反加一”,即可得到補碼:1111...101001110
題給為short型,故答案為1111 1111 0100 1110
例題
求0.1011 -0.1011的補碼
其實這是一種特殊計法,因為真正的浮點數儲存本就不存在補碼一說,具體請參考下一章。
這裡小數點前的±號代表的是符號位,所以實際就是相當於原碼的01011(不過還是得寫成0.1011)和11011(1.1011)
那麼按照上面的轉換規則就不難看出補碼了。
- 資料轉換
預設情況
常量被當作有符號數
如果希望是無符號數,在後面加上字尾U
0U, 4294967259U
混用unsigned和signed時,轉換成unsigned,所以-1>0U
- 資料擴充套件和截斷
有符號數的擴充套件會涉及到符號位擴充套件,無符號數直接擴充套件即可。
有符號數的截斷會被先當作無符號數截斷,然後轉化成有符號數理解,無符號數直接截斷。
- 資料溢位
無符號數加法溢位:$x+y<x$ (都是整數,溢位之後再怎麼加也趕不上從0開始加)
下面討論有符號數:
例題
int tadd_ok_bugy(int x, int y) { int sum = x + y ; return (sum-x == y) && (sum-y == x) }
指出此函式錯誤並修正它。
其實由於tadd也是個阿貝爾群,結果是封閉的,隨便找兩個數其實都滿足該條件。(試一試便可)
正解:
int tadd_ok (int x, int y) { int sum = x + y ; return !((x>0&&y>0&&sum<0) || (x<0&&y<0&&sum>0)) }
例題(接上)
int tsub_ok(int x, int y) { return tadd_ok(x, -y) ; }
指出改程式碼存在的錯誤。
其實這個在前面補碼的原理中我們就可以看到,Tmin既然是從-0這個數騰出來的一個補充數,那麼它的負數實際上還是它本身,這是無法改變的。以$[-8,7)$為例,-8是1000,取反加一仍然是1000,所以當y傳了這個值進去,那麼這次判定結果(是否溢位)必然相反。
正解:
int tsub_ok(int x, int y) { int diff = x-y; return !(x>=0&&y<0&&diff<0 || x<0&&y>0&&diff>0) // 0減正數 不會溢位 }
乘法溢位直接截斷,然後按型別理解。
因為左移相當於乘2,且速度快很多,所以編譯器往往會做出優化,u << 3==u * 8 ;(u << 5) – (u << 3) == u * 24
有符號數除以$2^k$相當於$x>>k=\lfloor \frac{x}{2^k} \rfloor$;為負數時,需要$\lceil \frac{x}{2^k} \rceil$(向上取整),此時相當於$(x + (1<<k)-1) >> k)=\lfloor \frac{(x+2^k-1)}{2^k} \rfloor$
1-4-float
- 浮點數表示法
Numerical Form: $(–1)^s M 2^E$
Sign bit s determines whether the number is negative or positive
尾數Significand M is normally a fractional value in the range [1.0,2.0).
階碼Exponent E weights value by power of two
Encoding
- MSB s is sign bit s
- exp field encodes E (but is not equal to E)
- frac field encodes M (but is not equal to M)
分以下幾種情況討論:
1-5-machine-arch
1-6-machine-intro
1-7-machine-basics
1-8-machine-control
條件控制
//有時間再更新