計算機編碼

計算機編碼指電腦內部代表文字、符號、字母或數字的方式。電子計算機的文數字編碼，是指在計算機硬體軟體中對於文字或數值的內部表示。通常數值會儲存為位元組，而以組成它們的位元數給以名稱。選擇數值和位元模式之間的編碼，可以使計算機的操作便利；計算機處理器指令集所使用的位元編碼，通常需要將其格式再轉換以供外界的使用者來判讀，例如列印和顯示。對於紙筆書寫看似相同的文字元號或數值，在不同型別的電子計算機處理器內部中，可能有不同的約定用於整數和實數。大多數計算都是使用適合處理器暫存器的數碼格式來執行，但是某些軟體系統允許使用多種儲存方式，來表示任意大數。位元、位元組、字組位元和無號整數.計算機的基本儲存單位是“位元”，透過開關變化設定表達值0或1。在有兩個位元的情況下可以得到四個不同的狀態：00 01 10 11如果有三個位，則有八種狀態：000 001 010 011 100 101 110 111每當增加一個位時，將得到兩倍的狀態。計算機使用不同數量的位元儲存不同種類的資訊。4個位元被稱為一“nybble”，8個被稱為一位元組，也有16，32，或更多位元組成的資訊計量單位。一個nybble可以為16種不同的情況編碼，例如數字0到15。大體上，使用任何序列的排列來表示不同的16種狀態是可以的，但在實際的應用通常是這樣的：0000 = 十進位制0 1000 = 十進位制80001 = 十進位制1 1001 = 十進位制90010 = 十進位制2 1010 = 十進位制100011 = 十進位制3 1011 = 十進位制110100 = 十進位制4 1100 = 十進位制120101 = 十進位制5 1101 = 十進位制130110 = 十進位制6 1110 = 十進位制140111 = 十進位制7 1111 = 十進位制15這樣的表示是很自然的，因為它符合我們所熟悉的十進位制數表示方法。例如，給定一個十進位制數：7531我們很自然地把它理解為：7 × 1000 + 5 × 100 + 3 × 10 + 1 × 1或者，使用10的冪來表示：7 × 103 + 5 × 102 + 3 × 101 + 1 × 100注意任何數的0次冪都是1。資料中的每個數字表示從0到9的值，這樣我們有10個不同的數字，那就是我們把它稱為“十進位制”的原因。每個數字可以透過10的某次冪來決定它的位置。這聽起來很複雜，但實際上並不是這樣的。這正是當您讀一個數字的使用認為是理所當然的事情，您甚至都不用仔細思考它。類似地，使用二進位制編碼就像上面所說的那樣，值13是這樣編碼的：1101每一個位置有兩個數字可以選擇，所以我們稱它為“二進位制”。因此，它們的位置是這樣決定的：1101 =1 × 23 + 1 × 22 + 0 × 21 + 1 × 20 =1 × 8 + 1 × 4 + 0 × 2 + 1 × 1 = 13注意這裡使用了2的冪：1、2、4和8。痴迷於計算機的人通常可以記住2的從2到16次冪，這並不是因為他們的記憶力，而是因為他們大量的使用這些數字：20 = 1 28 = 25621 = 2 29 = 51222 = 4 210 = 1,02423 = 8 211 = 2,04824 = 16 212 = 4,09625 = 32 213 = 8,19226 = 64 214 = 16,38427 = 128 215 = 32,768216 = 65,536注意的是，根據公制單位，值210 = 1,024通常被提及為“kilo”，或簡寫成“K”，所以很多2的高次冪通常可以簡寫成：211 = 2 K = 2,048212 = 4 K = 4,096213 = 8 K = 8,192214 = 16 K = 16,384215 = 32 K = 32,768216 = 64 K = 65,536同樣的，值220 = 1,024 x 1,024 = 1,048,576通常被簡寫成“M”(即兆)：221 = 2 M222 = 4 M而230曾被稱為“吉”，或“G”。下面我們將會大量使用這些修飾符號。有一個很微妙的話題。如果我們使用16位，我們可以得到65,536種不同的值，但是這些值是從0到65,535的。人們通常從1開始數數，但是計算機是從0開始計數的。因為這對它們來說更簡便。這個小問題有時也會使得計算機混淆。現在，我們得到了計算位的方法：雖然有這種限制，但是在計算機中對於簡單的增1計數來說，“無符號整數”還是十分有用的。它們對計算機來說是很容易處理的。通常計算機使用16位或32位無符號整數，通常被稱為“整數”。一個整數允許對從0到65,535的資料進行操作，而一個長整型允許對從0到4,294,967,295的數進行操作。八進位制和十六進位制數.現在讓我們討論一些偏外的話題：對二進位制數字的表示方法。計算機通常使用二進位制來表達資料，但是在實際中如果使用像這樣的二進位制：1001 0011 0101 0001那將是一件痛苦的事，並且很容易出錯。通常計算機使用一個基於二進位制的表達方式：八進位制，或更通常使用的，十六進位制。這一件聽起來挺狡猾但實際上又很簡單的事。如果不是這樣的話，我們就不會這樣使用了。在平常的十進位制體系中，我們有10數字按以下方式構成排列：0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...在八進位制中，我們只有八個數字按以下方式構成排列：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 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”。這些表示數值的方法都是表位置的系統，但是它們使用的不是像十進位制那樣的10，而是分別使用8和16。例如：八進位制756= 7 × 82 + 5 × 81 + 6 × 80= 7 × 64 + 5 × 8 + 6 × 1= 448 + 40 + 6 = 十進位制494十六進位制3b2= 3 × 162 + 11 × 161 + 2 × 160= 3 × 256 + 11 × 16 + 2 × 1= 768 + 176 + 2 = 十進位制946好了，如果您還不是那麼明白，不用擔心。我們想說明的是，對於八進位制來說，他們剛好和3位二進位制有一個完美的對應關係：000 = 八進位制0001 = 八進位制1010 = 八進位制2011 = 八進位制3100 = 八進位制4101 = 八進位制5110 = 八進位制6111 = 八進位制7類似的，一個十六進位制數剛好和一個4位的二進位制數對應。0000 = 十六進位制0 1000 = 十六進位制80001 = 十六進位制1 1001 = 十六進位制90010 = 十六進位制2 1010 = 十六進位制a0011 = 十六進位制3 1011 = 十六進位制b0100 = 十六進位制4 1100 = 十六進位制c0101 = 十六進位制5 1101 = 十六進位制d0110 = 十六進位制6 1110 = 十六進位制e0111 = 十六進位制7 1111 = 十六進位制f因此，把一個很長的二進位制數轉換成一個八進位制就變得很簡便，例如：把二進位制1001001101010001轉化成八進位制：1 001 001 101 010 001 二進位制 = 111521 八進位制轉換成十六進位制會更簡單：1001 0011 0101 0001 = 9351 十六進位制但是要把它轉換成十進位制就比較麻煩了。八進位制和十六進位制使得轉換二進位制機器級的數字變得簡單方便。有符號整數和補碼.在定義了無符號二進位制數後，我們就要著手定義負數了，或稱為“有符號整數”。最簡單的一個方法是保留一個位來表示數值的符號。這個“符號位”可以位於數值的最左邊，當然也可以位於數值的最右邊。如果這個符號位為0，表示數值是正的，如果這個符號位為1，表示數值是負的。這樣做是可以的，雖然從人類的角度來看是最明顯的解決方案，但是它對於計算機來說有可能帶來一些難度。例如，這種編碼使得0可以有正負兩種。人們可能對此感到不可思議，但是這對計算機來說是適應的。對計算機來說，更自然的表達方式是對給定的位數的二進位制數按其範圍分成兩半，其中前一半用來表示負數。例如，在4位數值中，你可以得到：0000 = 十進位制00001 = 十進位制10010 = 十進位制20011 = 十進位制30100 = 十進位制40101 = 十進位制50110 = 十進位制60111 = 十進位制71000 = 十進位制-81001 = 十進位制-71010 = 十進位制-61011 = 十進位制-51100 = 十進位制-41101 = 十進位制-31110 = 十進位制-21111 = 十進位制-1現在我們得到了一個“有符號整數”數字系統，使用所知道的，為了一些不是很重要的原因，“補碼”編碼方式。對16位有符號數字編碼來說，我們可以得到範圍為-32,768到32,767的有符號數字。對一個32位的有符號編碼系統來說，我們可以為從-2,147,483,648到2,147,483,647的數編碼。與只改變符號位來表示負數的編碼方式相比，“補碼”編碼方式與之有所不同。例如對於-5來說，只對符號位編碼，應該是：1101但是對於“補碼”編碼方式來說，則是：1011這對於符號編碼來說是-3。關於為什麼計算機要使用補碼這種編碼方式我們會在後面解釋。所以，現在我們可以以二進位制方式來表示正負兩種不同的數值。請記住對於一個二進位制數來說，只有兩種解釋方式。如果在記憶體中有一個這樣的二進位制數值：1101-- 這隻能解釋為十進位制的“13”或“-5”。定點小數.這種格式通常被用於商業計算；因為在這裡，丟棄小數位來記錄金錢是不能接受的。因此瞭解二進位制如何存貯小數是十分有用的。首先去我們必須決定要用多少位來存貯小數部分和多少位來儲存整數部分。假設我們使用32位來表示這種格式，那麼我們用16位表示整數部分，16位來表示小數部分。小數部分怎麼使用呢？這沿用了表示整數的方式：如果8位接下來是4位，是2位，1位，那麼當然接下來就是半位，1/4位和1/8位等等了。例如：整數位 小數位0.5 = 1/2 = 00000000 00000000.10000000 000000001.25 = 1 1/4 = 00000000 00000001.01000000 000000007.375 = 7 3/8 = 00000000 00000111.01100000 00000000有一點棘手的是，如果您要表達1/5，那您不能得到精確的數值表達方式。最好的方法只能是：13107/65536 = 00000000 00000000.00110011 00110011 = 0.1999969... 十進位制13108/65536 = 00000000 00000000.00110011 00110100 = 0.2000122... 十進位制然而不，您不能這樣做，即使您有更多的數位來表達。問題是，一些小數使用二進位制的方式不能精確地表達出來。除非您使用一個特殊的辦法。這個特殊的辦法是分別使用兩個數字來表達小數：一個是分子，一個是分母。然後您可以使用學校學習的加、減、乘、除來得到它們。然而，這些方法不能表達更高階的數字，或者如果這兩個分母的最小公倍數很大的話，那就難以使用。這就是使用定點小數表達小數的缺點。浮點小數.當我們使用了有符號和無符號的數值表達方式時。如果遇到連32位也不足以表達的大範圍的數，或也許可以表達，但我們必須為此放棄小數位時，我們可以選擇的以獲得更大範圍的數值的表達方式的方法是使用“浮點小數”格式而拋棄“定點小數”格式。在十進位制中，我們對以下的表達方式很熟悉：1.1030402 × 105 = 1.1030402 × 100000 = 110304.02或簡寫成：1.1030402E5這表示“1.103402乘以一個1後面跟著5個零的數”。我們可以得到一個確定的稱謂“尾數”的數值，也就是“冪級數”。如果我們使用一個負的冪級數，那就意味著乘以該正級數的倒數。例如：2.3434E-6 = 2.3434 × 10-6 = 2.3434 × 0.000001 = 0.0000023434使用這種定義的好處是我們可以得到更大範圍的數值，雖然尾數部分的精確度受到影響。相似的原理可以應用於二進位制中為計算機使用。人們設計了很多方式，但是作常用的是由美國電器和電子工程師協會定義的一種方法。它對64位浮點格式的定義是：下面我們使用一個例子來了解計算機如何使用記憶體的8位元組儲存這些數字：第0位元組： S x10 x9 x8 x7 x6 x5 x4第1位元組： x3 x2 x1 x0 m51 m50 m49 m48第2位元組： m47 m46 m45 m44 m43 m42 m41 m40第3位元組： m39 m38 m37 m36 m35 m34 m33 m32第4位元組： m31 m30 m29 m28 m27 m26 m25 m24第5位元組： m23 m22 m21 m20 m19 m18 m17 m16第6位元組： m15 m14 m13 m12 m11 m10 m9 m8第7位元組： m7 m6 m5 m4 m3 m2 m1 m0其中的“S”表示符號位，“X”表示指數位，“m”表示尾數位。一旦這些數字被讀取，它將轉換成：- 1023這個方式提供的數字範圍為：這種方式也定義了一些不是數字的值，例如“NaNs”。這通常用來返回表示數字溢位的資訊。通常您不會碰到它，所以我們也不會對它進行進一步討論。一些程式使用32位浮點小數。最普遍的是使用32位尾數，1位符號位，8位階碼和“超127”格式。它提供7位十進位制數字。第0位元組： S x7 x6 x5 x4 x3 x2 x1第1位元組： x0 m22 m21 m20 m19 m18 m17 m16第2位元組： m15 m14 m13 m12 m11 m10 m9 m8第3位元組： m7 m6 m5 m4 m3 m2 m1 m0數字轉換時使用：- 127它的範圍為：通常我們可以把32位的二進位制浮點數稱為“單精度”浮點數，而把64位的二進位制浮點數稱為“雙精度”浮點數。如果我們使用real的時候，通常表示雙精度的浮點數；而使用float的時候，我們通常指單精度的浮點數。但是要記住的是，浮點數在計算機的儲存是連續的：當計算機記憶體中有一個64位資料時，它可能是一個雙精度的浮點數，也可能是兩個單精度的浮點數，或4個有符號或無符號的整數，或其它8位的資料，這取決於計算機如何讀取它們。如果計算機把4個無符號整數以雙精度浮點小數方式讀出的話，它可以得到一個雙精度浮點小數，但這個資料可能是一個垃圾資料。所以，現在雖然我們已經解決了正、負數的存貯方式，但是對於浮點數來說，仍然存在一些與整數一樣的缺陷，例如：這意味著，如果您做浮點計算，較小的數字很可能被丟棄了。雖然這在平常來說並不明顯，但是如果您是做要求很高的數學分析工作，這些錯誤可能會累積起來，以至於最後得到的結果十分不準確。這個錯誤對進行數學研究的人來說十分重要，他們必須對誤差十分了解，以及研究一些辦法來減少誤差，並且應該可以估計到誤差的大小。順便說一句，“精度”問題與“範圍”問題不同，前者指的是有關尾數的表示範圍，後者指的是指數的表達範圍。如果您對這部分內容不理解，別擔心。這裡的要點是，計算機不是萬能的，它只是一部機器，並要符合一定的規則和受到一定的限制。雖然很多人對計算機抱有孩子似的信任，但是在計算機雖好的解決方法下也有一些不可避免的不精確。程式語言中的數.對於低階語言的程式設計者來說，他們要擔心有符號和無符號、定點和浮點數的運算。他們必須使用十分不同的程式碼來實現操作。但是，對高階語言的程式設計者來說，諸如LISP和Python提供了一些列諸如“有理數”、“複數”之類的抽象資料型別。而他們可以斷言他們的系統可以使用數學操作做正確的運算。由於運算子過載，數學運算可以應用於任何數字——無論是有符號的、無符號的、有理數、定點小數、浮點小數或複數。文字編碼：ASCII和字串.現在我們已經得到不同的方法來儲存資料了，那麼文字呢？我們怎麼儲存姓名、地址或寫給朋友的信件呢？當然，如果您還記得位是位的話，我們沒有理由不能使用位來表達字母“A”或“？”或“Z”之類的。因為很多計算機每次處理一個位元組，所以使用單位元組的資料來表達單個字母會很方便。我們可以使用這個：0100 0110 (hex 46)來表示字母“F”。計算機使用這樣的“字元編碼”來向顯示程式傳送要求的文字。下面是一個用來儲存西方字母的標準二進位制編碼，就是通常所說的“美國資訊交換標準碼”，下面的編碼為ASCII編碼，使用“d”表示十進位制編碼，“h”表示十六進位制程式碼，“o”表示八進位制程式碼：上面這個列表的最左邊有一個些奇怪的字元，例如“FF”和“BS”，這些都不是文字字元。相反，它們是控制字元，也就是說當這些字元傳送到特定的裝置時，它將產生一些動作。例如“FF”表示換頁，或彈出；“BS”表示退格，而“BEL”表示一個響聲。在一個文字編輯器中，它們會顯示成一個白色或黑色的方塊，或笑臉、音符或其它一些奇怪的符號。要打出這些字元，可以使用CTRL鍵和一個合適的程式碼。例如同時按住“CTRL”和“G”，或簡寫成“CTRL-G”或“^G”可以打出一個BEL字元。上面這個ASCII碼錶示定義了128個字元，這意味著ASCII碼只需要7位。但是，很多計算機都以位元組為單位儲存資訊。這個額外的一位可以定義第二個128個字集，一個“擴充套件”字集。在實際中，有很多不同的“擴充套件”字集，提供很多例如數學符號等的符號或非英語字元。這個擴充套件字集並沒有進行標準化，並經常會引起混淆。這個表格強調了這篇文章的主題：位就是位。這樣的話，您可以使用位來表示字元。您可以把特殊的程式碼描述成特殊的十進位制、八進位制和十六進位制，但是它們仍然是相同的程式碼。這些數值的表達，無論是十進位制、八進位制或十六進位制，都只是相同的位的表達。當然，您可能在一段話中表達很多的字元，例如：Tiger, tiger burning bright!這只是簡單的替換成ASCII碼，表示成：54 69 67 65 72 2c 20 74 69 67 65 72 20 62 75 ...計算機把這種ASCII“字串”以連續空間的“陣列”來儲存。一些應用程式可以包括一個二進位制數值表示字串的長度，但是更通常的做法是使用一個表示結尾的字元NULL（ASCII表中的0字元〕表示字串的結束。