1. 程式人生 > 其它 >ICS1期中考試複習

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

  1. MSB s is sign bit s
  2. exp field encodes E (but is not equal to E)
  3. 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

條件控制

//有時間再更新