整數與浮點數【詳解】(二)
1、截斷
圖1
在逆元中,爲什麼2w−x+x=0?從循環隊列看,是因爲2(w−1)-1+1又回到了起點,下面從位操作的觀點理解這一點並認識到逆元確實也是一種模運算。(有關逆元的相關知識參考整數與浮點數【詳解】(一))
如圖1是w位Umax+1的運算,可以看出產生了進位1,使位向量變成了w+1位。但w+1位並不符合一個w位的無符號數,因此機器將溢出的這一位進位1進行截斷,得到了全0的位向量即數字0。那麼截斷的本質是如何?考察一個w位無符號數,將其截斷爲k位,即:
B2Uw(x⃗)=i=0∑w−12ixi→B2Uk(x⃗)=i=0∑k−12ixi
注意到對任何i≥k,2imod2k=0,所以上式實際上是:
B2Uk(x⃗)=i=0∑k−12ixi=i=0∑w−12iximod2k=B2Uw(x⃗)mod2k
可以說,截斷的本質就是模運算,通過模運算把高於k位的所有數字置0,那麼逆元的本質就體現在整數的模運算:
圖2
無符號數的截斷定義爲:
假設一個w位位向量x⃗=[x(w−1),x(w−2),……x0],將其截斷爲k位位向量,則:
x′=xmod2k
其中x,x’分別爲截斷前後位向量對應的無符號數
有符號數的截斷比無符號數多一步Set Sign,如圖3,其本質與無符號數相同,但需要把截斷後的數設置一個負權表示有符號
圖3
有符號數的截斷定義爲:
假設一個w位位向量x⃗=[x(w−1),x(w−2),……x0],將其截斷爲k位位向量,則:
x′=U2T(xmod2k)
其中x’爲截斷後位向量對應的有符號數,x實際意義上是截斷前的有符號數,但在截斷時把它視爲無符號數進行截斷便於模運算且並不影響結果,換言之,有符號數的截斷就是把有符號數看成無符號數截斷後再轉爲有符號數
2、無符號數與有符號數之間的轉換
無符號數與有符號數間的區別僅在最高位權的正負,因此兩者的轉換也就是一位權值的變化,這個變化並不影響位向量本身。若最高位是1,那麼轉換前後會相差一個2w−1;若最高位是0,那麼轉換前後不變。
值得注意,執行一個運算的運算數若一個有符號而一個無符號,則C語言會隱式地將有符號數強制類型轉換爲無符號數
圖4
3、位擴展
與截斷相對應,當一個w位位向量x⃗=[x(w−1),x(w−2),……x0]要轉變爲一個w′位的位向量,就會在多出w′−w個的高位,這些高位的填充就是位擴展考慮的問題。
無符號數的位擴展是0擴展,有符號數的位擴展是符號擴展不同數據大小間數據的轉換,以及無符號數、有符號數間的轉換會影響程序行爲,甚至導致意想不到的結果。例如:
short sx =-12345
unsigned uy=sx
結果表明這裏類型轉換是先位擴展爲int32,再轉爲unsigned。由於sx符號位爲1,有符號數位擴展使高位全爲1,此時再轉爲無符號數相當於-12345加上了232,得到4294954951
在這個例子中還需要指出一點:符號擴展不影響真值。
從0xCFC7→0xFFFFCFC7似乎改變了數值,其實從理論上考慮並沒有產生影響:
B2Uw(x⃗)=−xw−12w−1+i=0∑w−22ixi
將這個有符號數向左擴展一位,得到
B2Uw+1(x⃗)=−xw2w+xw−12w−1+i=0∑w−22ixi
當xw−1=0時顯然有B2Tw(x⃗)=B2Tw+1(x⃗);當xw−1=1時,−2w+2w−1=−2w−1=−xw−12w−1,即仍然有B2Tw(x⃗)=B2Tw+1(x⃗)。進一步由歸納法得到符號擴展不影響真值。