計算機用戶的壹個普遍誤解是計算機數值計算的絕對準確性。也就是說,如果妳乘以:
3 × (1/3)
您期望的準確結果是1。另壹方面,妳發現計算機沒有給出這個結果,但它只是壹個近似值,類似於0.4000000000005
這似乎是系統的壹個“bug”,但更令人驚訝的是,是的,計算機就是這樣工作的(計算機代數系統除外)。本文將詳細解釋這個問題。
位、字節、半字節和無符號整數
幾乎所有的計算機用戶都知道“位”的概念。在計算機中,表達式值0或1通過切換來設置。如果您有兩個位可供選擇,您可以輕松獲得四種不同的狀態:
00 01 10 11
如果您有三位,您可以用八種狀態來表示它們:
000 001 010 011 100 101 110 111
每增加壹點,妳就會得到兩倍的狀態。
許多計算機使用八位來表示信息,而其他計算機則多了八位,例如16位、32位或64位。通常以八位為壹組作為基本單位,並使用另壹個詞“字節”。計算機的處理器壹次處理壹位或多位信息。存儲器使用壹個或多個八位字節來存儲數據。
事實上,在某些情況下使用四位來處理問題更方便。這種四位數據通常被稱為“四位字節”。但事實上,“bit”比“nybble”更常用。
壹個nybble可以編碼16種不同的情況,例如數字0到15。壹般來說,可以使用任何序列排列來表示不同的16狀態,但在實際應用中通常是這樣的:
0000 =十進制0 1000 =十進制8 0001 =十進制1 =十進制9 0010 =十進制2 1010 = 1011 =十進制4 654383 0110 =十進制6 1110 =十進制14 0111 =十進制7 1166。
這種表示是自然的,因為它符合我們熟悉的十進制數表示方法。例如,給定壹個十進制數:
7531
我們自然將其理解為:
7 × 1000 + 5 × 100 + 3 × 10 + 1 × 1
或者,使用10的冪來表示:
7 × 10 3 + 5 × 10 2 + 3 × 10 1 + 1 × 10 0
請註意,任何數字(除了0)的0次方都是1。
數據中的每個數字代表壹個從0到9的值,因此我們有10個不同的數字,這就是為什麽我們稱之為“十進制”。每個數字都可以用10的冪來確定。聽起來很復雜,但事實並非如此。當妳閱讀壹個數字的用法時,這正是妳認為理所當然的,妳甚至沒有仔細考慮過它。
類似地,如上所述,使用二進制編碼,13的值編碼如下:
1101
每個位置有兩個數字可供選擇,因此我們稱之為“二進制”。因此,它們的位置確定如下:
1101 =
1 × 2 3 + 1 × 2 2 + 0 × 2 1 + 1 × 2 0 =
1×8+1×4+0×2+1 = 13(十進制)
請註意,這裏使用的是2的冪:1、2、4和8。癡迷於計算機的人通常能記住從2到16的2的冪,這不是因為他們的記憶力,而是因為他們經常使用這些數字:
2 0 = 1 2 8 = 256 2 1 = 2 2 9 = 512 2 2 = 4 2 10 = 1 024 2 3 = 8 2 11 = 2 048 2 4 = 16 2 654 38+02 = 4 096 2 5 = 32 2 13 = 8 192 2 6 = 64 2 14 = 16 384 2 7 = 128 2 15 = 32 768 2 16 = 65 536
請註意,根據公制單位,值2 10 = 1 024通常稱為“千克”或縮寫為“k”,因此2的許多高次冪通常可以縮寫為:
2 11 = 2K = 2 048 2 12 = 4K = 4 096 2 13 = 8K = 8 192 2 14 = 16K = 16 384 2 15 = 32K = 32 768 2 16 = 64K
同樣,值2 ^ 20 = 1 ^ 024 x 1 ^ 024 = 1 ^ 048 576通常縮寫為“m”:
2 21 = 2米2 22 = 4米
而2 ^ 30壹度被稱為“吉”或“克”。我們將在下面大量使用這些修飾語。
有壹個很微妙的話題。如果我們使用16位,我們可以得到65 536個不同的值,但這些值的範圍從0到65 535。人們通常從1開始計數,但計算機從0開始計數。因為這對他們來說更容易。這個小問題有時會讓計算機感到困惑。
現在,我們有了計算位數的方法:
您只能在所有位的範圍內執行算術運算。換句話說,如果您使用的是16位,則不能對65 535或更大的數據進行操作,否則會出現“數據溢出”錯誤。這個術語表示您所做的是“有限精度”操作。
小數不能用這種編碼來表示。您只能使用非十進制的“整數”。
負數不能用這種編碼來表示。所有數字都是“無符號數字”
盡管有這種限制,“無符號整數”對於計算機中1的簡單計數仍然非常有用。它們易於計算機處理。通常計算機使用16位或32位無符號整數,通常稱為“整數”或“長整數”。整數允許對0到65,535的數據進行運算,而長整數允許對0到4,294,967,295的數字進行運算。
八進制和十六進制數字
現在讓我們討論壹些無關的話題:二進制數的表示。計算機通常使用二進制來表示數據,但實際上,如果您像這樣使用二進制:
1001 0011 0101 0001
那將是壹件痛苦的事情,而且容易出錯。通常計算機使用基於二進制的表達式:八進制,或者更常見的十六進制。
這個聽起來很狡猾,但實際上非常簡單。如果不是因為這個,我們不會這樣使用它。在通常的十進制系統中,我們有10個數字(0到9),排列方式如下:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...
在八進制中,我們只有八個數字(0到7),排列如下:
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 ...
也就是說,八進制的“10”相當於十進制的“8”,八進制的“20”相當於十進制的“16”,以此類推。
在十六進制中,我們只有十六個數字(0到9,然後從A到F),排列方式如下:
0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16...
換句話說,十六進制的“10”相當於十進制的“16”,十六進制的“20”相當於十進制的“32”。
這些數值方法都是表位置系統,但它們使用8和16,而不是像decimal那樣使用10。例如:
八進制756
= 7 × 8 2 + 5 × 8 1 + 6 × 8 0
= 7 × 64 + 5 × 8 + 6 × 1
= 448+40+6 =十進制494
十六進制3b2
= 3 × 16 2 + 11 × 16 1 + 2 × 16 0
= 3 × 256 + 11 × 16 + 2 × 1
= 768+176+2 =十進制946
如果妳不明白,別擔心。我們想解釋的是,對於八進制來說,它們與三位二進制完全對應:
000 =八進制0
001 =八進制1
010 =八進制2
011 =八進制3
100 =八進制4
101 =八進制5
110 =八進制6
111 =八進制7
類似地,壹個十六進制數只對應壹個4位二進制數。
0000 =十六進制0 1000 =十六進制8 0001 =十六進制1 =十六進制9 0010 =十六進制2 1010 = 1011 =十六進制b 0100 =十六進制4 16538十六進制6 1110 =十六進制e 0111 =十六進制7 11 =十六進制f。
因此,將很長的二進制數轉換為八進制數非常簡單,例如將二進制數1001001010101轉換為八進制數:
1 001 001 1 01 001二進制= 11八進制。
轉換成十六進制更容易:
1001 001 01 001 0001 = 9351十六進制。
但是轉換成十進制(37 713)比較麻煩。八進制和十六進制使轉換二進制機器級別的數字變得容易。
帶符號整數和補碼
定義了無符號二進制數之後,我們將開始定義負數,即“有符號整數”。最簡單的方法是保留壹位來表示數值的符號。這個“符號位”可以位於值的最左邊,當然也可以位於值的最右邊。如果符號位為0,則表示該值為正,如果符號位為1,則表示該值為負。
這樣做是可能的。盡管從人類的角度來看這是最明顯的解決方案,但它可能會給計算機帶來壹些困難。例如,這種編碼使正負零都成為可能。人們可能對此感到不可思議,但它適用於計算機。
對於計算機來說,更自然的表達方式是將給定位數的二進制數根據其範圍分成兩半,其中前半部分用於表示負數。例如,在壹個4位數中,您可以得到:
0000 =十進制0 0001 =十進制1 0010 =十進制2 0011 =十進制3 0100 =十進制4 0101 = 011 =十進制7 1000 =十進制-8 138+0101 = Decimal-3 110 = Decimal-2 11111 = Decimal-65438+。
現在我們有了壹個“帶符號整數”的數字系統,由於壹些不重要的原因,它使用了已知的“補碼”編碼方法。對於16位有符號數字編碼,我們可以得到-32 768到32 767範圍內的有符號數字。對於32位有符號編碼系統,我們可以對從-2 147 483 648到2 147 482 647的數字進行編碼。
與僅改變符號位來表示負數的編碼方法相比,“補碼”編碼方法有所不同。例如,對於-5,僅編碼符號位,應為:
1101
但是對於“補碼”編碼方法,它是:
1011
這是符號編碼的-3。我們稍後將解釋為什麽計算機使用補碼編碼。
所以,現在我們可以用二進制的方式表示兩個不同的值,正的和負的。記住解釋二進制數只有兩種方法。如果內存中有這樣的二進制值:
1101
-這在十進制中只能解釋為“13”或“-3”。
不動點
這種格式通常用於商業計算(例如,在電子表格或COBOL中);因為在這裏,拋棄小數點來記錄貨幣是不可接受的。因此,了解二進制如何存儲小數非常有用。
首先,我們必須決定用多少位存儲小數部分,用多少位存儲整數部分。假設我們用32位來表示這種格式,那麽我們用16位來表示整數部分,用16位來表示小數部分。
小數部分怎麽用?這遵循表示整數的方式:如果8位後跟4位,則是2位和1位,然後當然是半位、1/4位和1/8位等等。
例如:
整數小數位0.5 = 1/2 = 0000000000000.10000000000000005438+0.25 = 1 1/4 = 0000000000000000000000000 7
有點棘手的是,如果要表示1/5(十進制0.2),則無法得到準確的數值表達式。最好的辦法只能是:
13107/65536 = 0000000000000.00111101111110065438.
13108/65536 = 0000000000000.00111101111101065438 = 0.
然而,不,妳不能只是做它,因為妳有更多的數字來表達它。問題是有些小數不能用二進制精確表示。除非妳用特殊的方法。這種特殊的方法是用兩個數字來表示小數:壹個是分子,另壹個是分母。然後妳可以用學校裏學過的加減乘除來得到它們。但是,這些方法無法表示更高級別的數字(如平方根),或者如果這兩個分母的最小公倍數很大,則很難使用。這就是用定點小數表示小數的好處。
浮點十進制
當我們使用有符號和無符號數值表達式時。如果我們遇到壹個範圍很大的數字,甚至32位都不足以表達它們,或者我們可能能夠表達它們,但我們不得不為此放棄小數位數,我們可以選擇的獲得更大範圍的數字表達式的方法是使用“浮點小數”格式而不是“固定小數”格式。
在十進制系統中,我們熟悉以下表達式:
1.1030402 × 10 5 = 1.1030402 × 100000 = 110304.02
或縮寫為:
1.1030402E5
這意味著“1.103402乘以壹個數字1後跟五個零”。我們可以得到壹個確定的數值(1.1030402)稱為尾數,並將其乘以10(E5,代表10 5或100 000)的某個冪級數,即冪級數。如果我們使用負冪級數,它意味著乘以正級數的倒數。例如:
2.3434 e-6 = 2.3434×10-6 = 2.3434×0.00001 = 0.0000023434
使用這個定義的好處是我們可以得到更大範圍的值,盡管尾數部分的準確性會受到影響。類似的原理也適用於計算機使用的二進制系統。已經設計了許多方法,但通常使用美國電氣和電子工程師協會定義的壹種方法。它將64位浮點格式定義為:
11二進制表示索引,使用“超級1023”的格式。這種格式允許將指數表示為從0到2047的無符號數,但在獲得真實值之前,必須將其從1023中減去;
52位尾數,用無符號數字表示;
符號位;
讓我們用壹個例子來理解計算機如何使用8位內存來存儲這些數字:
0號:sx 10x 9 x7 xxx5 x 4 1號:x3x2x 1x0m 51m 50m 49m 48 2號:m47m 46m 45m 44m 43m 41m 40 3號:M39m38m38。35 m34 m33 m32第四名:m31 m30 m29 m28 m27 m26 m25 m24第五名:m23m 22m 21m 20m 19m 17m 16第六名:M15m6556。13m 12m 1m 10m 9 M8第七名:m7 m6 m5 m4 m3 m2 m1 m0。
其中“s”代表符號位,“x”代表指數位(秩碼?),“m”表示尾數。壹旦這些數字被讀取,它將被轉換為:
& ltsymbol》×(1+& lt;分數尾數》;)×2 & lt;訂單代碼》- 1023
此方法提供的數字範圍是:
最大值和最小值
正數是1.7991346231e+308484+0246534
負數-4.94065645412465 e-324-1.791331e+308。
該方法還定義了壹些不是數字的值,例如“NaNs”(“不是數字”)。這通常用於返回指示數字溢出的信息。通常妳不會碰它,所以我們不會進壹步討論它。壹些程序使用32位浮點小數。最常見的是使用32位尾數、1位符號位、8位代碼和“超級127”格式。它提供7個十進制數字。
第0名:S x7 x6 x5 x4 x3 x2 x1No1號:x0m22m 21m20m 19m 17m 16號2號:M15m65438+。第三名:m7 m6 m5 m4 m3 m2 m1 m0。
用於數字轉換:
& ltsymbol》×(1+& lt;分數尾數》;)×2 & lt;訂單代碼》- 127
其範圍是:
最大值和最小值
正數3.402823E+38 2.802597E-45
負數-2.802597e-45-3.423e+38
通常,我們可以將32位二進制浮點數稱為“單精度”,將64位二進制浮點數稱為“雙精度”。如果我們使用real,它通常表示壹個雙精度浮點數;使用float時,我們通常指單精度浮點數。
但請記住,位是位,它們在計算機中的存儲是連續的。當計算機內存中有壹個64位數據時,它可能是壹個雙精度浮點數、兩個單精度浮點數、四個有符號或無符號整數或其他8位數據,這取決於計算機如何讀取它們。如果計算機將四個無符號整數讀取為雙精度浮點小數,則可以得到壹個雙精度浮點小數,但此數據可能是垃圾數據。
因此,盡管我們現在已經解決了正數和負數的存儲模式,但浮點數仍然存在壹些類似整數的缺陷,例如:
和整數壹樣,浮點數也有範圍。雖然我們得到的範圍比整數大得多,但它仍然是有限的。如果您試圖將兩個非常大的數字相乘,可能會出現“數據溢出”錯誤。而且如果用壹個小數字除以壹個大數字,可能會使索引的值出錯,從而導致“數據下溢”的錯誤。最大值通常被稱為“機器無窮大”,因為這是計算機可以處理的最大數。
另壹個問題是準確性。盡管您有15個數字來表示壹個非常大的數字,但在對其執行四則運算時,它們可能會丟棄壹些數字而不給妳任何提示。這意味著,如果您將壹個非常小的數字加到壹個非常大的數字上,計算機會將其丟棄,因為該數字太小,無法以15或16的精度顯示。如果妳在計算時得到壹個非常奇怪的數字,妳可能需要檢查妳的數據範圍是否合適。
這意味著如果進行浮點計算,較小的數字很可能會被丟棄。雖然這在平時並不明顯,但如果您正在進行要求苛刻的數學分析,這些錯誤可能會積累起來,以至於最終的結果非常不準確。
這個誤差對於從事數學研究的人來說非常重要。他們必須非常了解誤差並研究壹些減少誤差的方法,他們應該能夠估計誤差的大小。
順便說壹下,“精度”的問題不同於“範圍”的問題。前者指尾數的表達範圍,後者指指數的表達範圍。
另壹個不太明顯的錯誤是浮點數的二進制和十進制並不完全相等。如果您運算的數字是2的冪級數的倒數,例如0.75,則可以在二進制中準確地標記為0.11,因為它正好是1/2+1/4的值。然而,不幸的是,妳通常可能得不到這樣壹個合適的數字,也就是說,計算機會丟棄壹些數字,例如,要表示0.1,妳只能使用無窮無盡的二進制十進制0.00011001...
如果妳不理解這壹部分,不要擔心。這裏的重點是計算機不是萬能的,它只是壹臺機器,它必須符合壹定的規則並受到限制。盡管許多人對計算機抱有孩子般的信任,但在計算機的良好解決方案下,仍有壹些不可避免的不準確性。
編程語言中的數字
對於低級語言的程序員來說,他們不得不擔心有符號和無符號、定點和浮點運算。他們必須使用非常不同的代碼來實現操作。
但是,對於程序員來說,高級語言,如LISP和Python提供了壹些抽象數據類型,如“有理數”和“復數”。他們可以斷言他們的系統可以使用數學運算來進行正確的運算。由於運算符的重載,數學運算可以應用於任何數字——無論是有符號數、無符號數、有理數、定點小數、浮點小數還是復數。
文本編碼:ASCII和字符串
既然我們有了不同的存儲數據的方法,那麽文本呢?我們如何存儲給朋友的姓名、地址或信件?
當然,如果妳記得壹位就是壹位,我們沒有理由不能用壹位來表示字母“a”或“?”得到壹個“z”或其他東西因為許多計算機壹次處理壹個字節,所以使用單字節數據來表示單個字母很方便。我們可以用這個:
0100 0110(十六進制46)
為了表示字母“f”,計算機使用這種“字符編碼”將所需的文本傳送給顯示程序。
以下是存儲西文字母的標準二進制代碼,通常稱為“美國信息交換標準代碼”(縮寫為“ASCII”)。以下代碼是ASCII代碼,其中“D”表示十進制代碼,“H”表示十六進制代碼,“O”表示八進制代碼:
ASCII代碼表_ _ _ _ _ _ _ _ _ _ _ _代碼表
ch CTL d h o ch d h o h o ch d h o h o h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h o c h c h o c h o c h o c h c h o c h c h o c h o c h c h o c h o c h o c h o c h o c h o c h o c h o c h c h o c h o c
新^@ 0 0 sp 32 20 40 @ 64 40 100‘96 60 140新^A 1 1!33 21 41 a 65 41 1 a 97 61 1 stx ^b 2 2 2“34 22 42 b 66 42 102 b 98 62 142 ETX ^c 3 3 3 # 35 23 43 c 6338 26 46 f 70 46 106 f 102 66 146貝爾^G
^h 8 810(40 28 50小時72 48 10小時104 68 150 ht ^i 9 911) 42 2a 52j 74 4a 112j 106 6a 152 vt ^k 11 b 13 _ 43 2b 53k 75 4b 113k 107 6b 153 ff ^l 12 c 46 2e 56n 78 4e 116n 10 6e 156 si ^o 15 f 17/47 2f 57 o 79 4f 117 o 11116f 15438
德爾^p 16 10 20 48 30 60 p 80 50 120 p 12 70 160 DC 1 ^q 17 11 21 1 49 31 6666 54 124t 116 74 164納克^u 21 15 25 53 35 65 u 85 55 125 u 117 75 165 syn ^v 22 16 26 654 36
^x 24 18 30 8 56 38 70 x 88 58 130 x 120 78 170 ^y 25 19 31 9 57 39 71y 89 59 1y 121 777759 3b 73【91 5b 133 { 123 7b 173 fs ^\ 28 1c 34 & lt;60 3c 74 \ 92 5c 134 124 7c 174 GS ^】29 1d 35 = 61 3d 75】93 5d 135 } 125 7d 175 RS ^^ 30 1e 36》62 3e 76 ^ 94 5e 136 ~ 126 7e 176美國^_ 31 1f 37?63 3f 77 _ 95 5f 137 DEL 127 7f 177 _ _ _ _ _ _ _ _ _ _ _
上面列表的最左邊有壹個奇怪的字符,例如“FF”和“BS”,它們不是文本字符。相反,它們是控制字符,這意味著當這些字符被發送到特定設備時,它們將產生壹些動作。例如,“FF”表示頁面更改或彈出;“BS”的意思是退格,而“BEL”的意思是壹個音。在文本編輯器中,它們將顯示為白色或黑色的正方形、笑臉、註釋或其他奇怪的符號。要鍵入這些字符,您可以使用CTRL鍵和合適的代碼。例如,同時按住“CTRL”和“G”,或者縮寫為“CTRL-G”或“G”可以鍵入壹個BEL字符。
上述ASCII碼意味著定義了128個字符,這意味著ASCII碼只需要7位數字。然而,許多計算機以字節存儲信息。這個額外的位可以定義128的第二個詞集,即“擴展”詞集。
在實踐中,有許多不同的“擴展”單詞集,它們提供了許多符號,如數學符號或非英語字符。這種擴展的詞集是不規範的,經常會造成混亂。
這張表強調了本文的主題:位就是位。在這種情況下,您可以使用位來表示字符。您可以將特殊代碼描述為特殊的十進制、八進制和十六進制,但它們仍然是相同的代碼。這些值的表達式,無論是十進制、八進制還是十六進制,都只是同壹位的表達式。
當然,妳可以在壹個段落中表達許多字符,例如:
虎虎灼灼亮!
這只是由ASCII碼代替,ASCII碼表示為:
54 69 67 65 72 2c 20 74 69 67 65 72 20 62 75...
計算機將這個ASCII“字符串”存儲為連續空間的“數組”。壹些應用程序可以包含壹個二進制值來指示字符串的長度,但更常見的是使用字符null(ASCII表中的0字符)來指示字符串的結尾。
請參考: