在寫數字的時候,表示負數很簡單,就加個負號就好了。那在電腦中該怎麼表示負數?
最簡單的方式是用最高位元來表示正負號,0 代表正,1 代表負,像是如果用 8 個位元來表示一個數,1000 0101
,1000 0011
,但這樣會發生一個問題,就是表示 1
或 0
,只要其他位都是 0
,這樣它就是表示
先用一個不那麼位元的想法來想,有
這樣做有一個好處,就是既然我們是在模
回到位元的看法,
0000 0001
的補數是 1111 1110
0101 1010
的補數是 1010 0101
在 C++ 中,~
這個運算子就是用來做這件事情。
而
0000 0001
的補數是 1111 1110
,二補數是 1111 1111
0101 1010
的補數是 1010 0101
,二補數是 1010 0110
0000 0000
的補數是 1111 1111
,加 1 後是 1 0000 0000
,二補數是 0000 0000
1000 0000
的補數是 0111 1111
,二補數是 1000 0000
這就是目前最常見的電腦儲存有號(正負)整數的方式,這裡說的二補數的字面上的值,就是我們剛剛說的用同餘得出來的數字。
C++ 中常見的整數型態範圍是這樣:
(unsigned
開頭的是無號的,也就是只有
型態 | byte 數 | 最大整數 | 最小整數 |
---|---|---|---|
char | 1 | 127 | -127 |
int | 4 | 2147483647 | -2147483648 |
long long | 8 | 9223372036854775807 | -9223372036854775808 |
unsigned int | 4 | 4294967295 | 0 |
unsigned long long | 8 | 18446744073709551615 | 0 |
建議大概記一下這些的範圍,像是 int
的最大值大約是 long long
的最大值大約是
接下來,有個特殊狀況,就是有兩個數取二補數後會跟原本一樣,這兩個數分別是
結論:
事實上所有整數進位制都可以套用類似二補數的規則,
這可以幹嘛呢?就是大數運算啦,以前大數運算還要多寫減法,現在只要寫加法就夠了!算
會存整數之後我們也要存小數,我們會用一種叫浮點數的東西來存它。用來規定浮點數表示方式的標準叫 IEEE 754,大部分程式語言都會按照這個標準。
浮點數是用類似科學記號的方式來儲存,只是換成二進位而已。用來儲存一個浮點數的記憶體由高位(左)到低位(右)被分成三段: - 符號位,只佔一個位元,0
表示此數為正,1
表示此數為負。 - 指數域,實際表示的值是指數域儲存的值減去指數偏移量,
若指數域所表示的指數值是
注意到負指數不是用二補數表示,而是減去指數偏移量。若指數偏移量是
為小數域的長度是有限的,但小數有無限小數,無限小數中又有循環小數和無理數,因此會發生不精確的問題,造成計算和判斷上的錯誤,遇到這種狀況有這幾種辦法: - 盡量不要用到小數,需要做運算的話,如果不需要做到太多難做的操作(例如乘法就是很簡單的操作),可以先用分子分母分開存的方式來計算,要輸出的時候再換成小數就好。 - 判斷一個浮點數是否等於一個值的時候,允許一個誤差範圍(相差小於一個極小的數),例如: 1
2double a = /*...*/;
if(a == 0){/*...*/}1
2double a = /*...*/;
if(fabs(a - 0) < 1e-9){/*...*/}
因為浮點數利用科學計號的方式儲存一個數,因此它除了可以表示分數以外,也可以表示一個極大的整數。
以下是 C++ 常見的浮點數型態,注意 double
的有效位數並不比 long long
來得長。
資料型態 | 指數域長度(bit) | 指數偏移量 | 小數域長度(bit) |
---|---|---|---|
float | 8 | 127 | 23 |
double | 11 | 1023 | 52 |
前面有提到當
指數為 -1 / 1e200 / 1e200
,不過比較的時候是不會出事的。
指數為 0
,符號位為正表示正無窮,為負表示負無窮,需要它的話,在 C++ 中可以用 INFINITY
來得到,它在 math.h
裡面,只是在競程上沒啥用途,頂多就是除以
Not a Number 的縮寫,指數為 0
,在反三角函數丟一些超出定義域的數字時會跑出這東西。
有兩個很大的型態叫 __int128
和 long double
,前者是 128 位元整數,可以存到大約
至於 long double
是一個非標準的浮點數,通常有 80 位元,指數域 15 位、小數域 64 位,也就是說它可以不失任何精度地存下 long long 範圍內的數字。既然它是非標準的東西,就代表它實際長怎樣依編譯器而定。它可以在 Windows 用、可以輸入輸出,可以當一般的浮點數型態用。