tft每日頭條

 > 生活

 > 計算機中的原碼反碼補碼

計算機中的原碼反碼補碼

生活 更新时间:2024-10-01 14:03:41

人們使用計算機處理信息。無論被處理信息的實質形态如何千差萬别,計算機内部隻能處理離散化的編碼後的數據。目前,計算機系統内部的所有數據均采用二進制編碼。

常見的數有整數和實數之分,整數的小數點固定在數的最右邊,通常省略不寫,而實數的小數點則不是固定的。但是,計算機中隻能表示0和1,無法表示小數點,因此計算機中表示數值數據必須要解決小數點的表示問題。我們通過約定小數點的位置來解決該問題。小數點位置約定在固定位置的數稱為定點數,小數點位置約定為可以浮動的數稱為浮點數。

1 定點數的表示

在明确了進位制和小數點位置的約定之後,整數在計算機中的表示還有一個正負号如何表示的問題要解決。針對這一問題,原碼和補碼這兩種編碼規則采用了不同的解決思路。

1.1 原碼

數的原碼表示采用“符号-數值”的表示方式,即一個形如的原碼表示,最高位是符号位,0表示正數,1表示負數;其餘位表示數值的絕對值。如果是0,則A表示正數;如果是1,則A表示負數。例如,對于 19和-19這兩個數,如果用8位二進制原碼表示,則 19的原碼是,-19的原碼是。

原碼表示有兩大優點:

1)與人們日常記錄正負數的習慣接近,與真實數值之間的對應關系直觀,利于與真實數值相互轉換。

2)原碼實現乘除運算比較簡便直接。

但是原碼表示亦存在兩個缺點:

1)存在兩個0,即一個 0,一個-0。這不僅有悖于人們的習慣,也給使用帶來不便。

2)原碼的加減運算規則複雜,這對于邏輯實現的影響很大。在進行原碼加減運算時,需要首先判斷是否為異号相加或同号相減的情況,如果是的話則必須先根據兩個數的絕對值的大小關系來決定結果的正負号,再用絕對值大的數減去絕對值小的數。

權衡上述利弊,現代計算機中基本不使用原碼來表示整數。原碼僅在表示浮點數的尾數部分時采用。

1.2 補碼

補碼是定點數的另一種表示方法。現代計算機中基本都是采用補碼來表示整數。它最大的好處就是可以用加法來完成減法運算,實現加減運算的統一。這恰好解決了原碼表示所存在的最大問題。

在補碼表示中,其最高位同原碼一樣也作為符号位,0表示正數,1表示負數。補碼表示和原碼表示的差異在于其數值的計算方法。對于一個形如的補碼表示,其值等于。如果是0,則補碼和原碼一樣,A表示正的;如果是1,則A表示減去(共n-1個0)得到的數。(A未考慮符号位)

這裡介紹一個原碼和補碼之間的轉換方法:最高位為0時,原碼與補碼相同;最高位是1時,原碼的最高位不變,其餘位按位取反後末位加1。舉個例子,譬如 19這個數,如果用8位二進制原碼表示是00010011,最高位是0,所以其二進制補碼也是00010011。那麼對于-19這個數,其原碼就是把 19原碼的最高位從0變為1,即10010011。在求-19的補碼時,原碼最高位的1保持不變,原碼餘下的7位0010011按位取反得到1101100,末位再加一個1,得到1101101,最終得到-19的8位補碼是11101101,這個值實際上是由 19的8位補碼減去10000000得到的。(00010011-10000000 = - (10000000-00010011)=-1101101)

求一個數的補碼是個取模運算。

n 進制基數就是 n模的餘數就是 0, 1, …, n-1

“取模”實質上是計量器産生“溢出”的量,它的值在計量器上表示不出來,計量器上隻能表示出模的餘數(取模);任何有模的計量器,均可化為加減法運算。

“模”是指一個計量系統的計數範圍,如時鐘,12個整點為計算範圍,則模為12。

在12模的時鐘中,假設當前時針指向10點,而準确時間是6點,調整時間可有以下兩種撥法:

① 倒撥4小時,即:

10-4=6

(10-4) mod 12 = 6

② 順撥8小時:

10 8=12 6=6

(10 8) mod 12 = 6

在以12模的系統中,加8和減4效果是一樣的;因此凡是減4運算,都可以用加8來代替。對“模”而言,8和4互為補數。實際上以12模的系統中11和1、10和2、9和3、7和5、6和6都有這個特性;共同的特點是兩者相加等于模

一個int類型的整數,在32位系統中,用4個字節,32個位來計量,其模為2^32。在模範圍内能表達的有 [0, 2³²-1]。在C語言中,也有不考慮符号的整數類型unsigned int,将全部的32位用來表示數,而沒有符号位一說。相當于就是整數的絕對值,因為現實世界中某些數的模拟,是沒有負數的。

如果要表示負數,也就是C的signed int,則必須有符号位,也就是上述的的補碼方案。正數 負數正好達到模的溢出閥值2³²,這也是在計算機中負數是用補碼方式表達的原因。

下面用一段代碼來表示上述的一些關系:

#include <stdio.h> #include <cmath> void complement() { int a = 19; // 0 0000000 00000000 00000000 00010011 int b = -19; // 1 1111111 11111111 11111111 11101101 unsigned int c = 0xffffffff-19 1; // 0xffffffff 1是int的模,unsigned不使用符号位 int d = a c; // 模溢出 //unsigned int e = pow(2,31)-19 pow(2,31);// pow(2,31)-15是非符号位取反 1, // 後面的 pow(2,31)是符号位取反 // pow(2,31) pow(2,31) = pow(2,32),int的模 unsigned int e = (1<<31)-19 (1<<31); // (1<<31)是pow(2,32)的簡便寫法 if(b == c) // b會提升為unsigned,二進制串按unsigned編碼解釋 printf("a補 = 模數(z^(sizeof(a)*8))-a\n"); else printf("not the same value!"); if(d == 0) printf("原碼加其補碼後其值溢出後為0\n"); printf("%d,%d\n",c,e); } int main() { complement(); while(1); return 0; } /* output: a補 = 模數(z^(sizeof(a)*8))-a 原碼加其補碼後其值溢出後為0 -19,-19 */

利用補碼基于模運算的這個特點,可以把減法轉換成加法來做,因此在計算機中不用把加法器和減法器分開,隻要有加法器就可以做減法。

2 浮點數的表示

計算機中用于數據存儲、傳輸和運算的部件的位數都是有限的,所以采用定點數表示數值數據時有一個不足之處,就是表示範圍有限,太大或太小的數都不能表示。同時定點數表示精度也有限,用定點做除法不精确。此外,定點數也無法表示數學中的實數。所以,計算機還定義了浮點數,用來表示實數并彌補定點數的不足。

2.1 二進制的科學記數法

在具體介紹計算機浮點數表示規格前,我們先回憶一下日常書寫實數時所采用的科學記數法。譬如可以記為,可以記為。一個采用科學記數法表示的數,如果尾數沒有前導零且小數點左邊隻有一位整數,則可稱為規格化數。既然我們可以用科學記數法來表示十進制實數,也可以用科學記數法來表示二進制實數。其一般的表示形式為:

其中s表示符号,f為尾數域的值,e為指數域的值。

譬如二進制實數的科學記數法表示:

2.2 IEEE 754浮點數标準

計算機中的浮點數表示沿用了科學記數法的表示方式,即包含了符号、尾數和階碼三個域。符号用一位二進制碼表示,0為正,1為負。然而在計算機内部位寬是有限的,餘下的尾數和階碼兩者間存在一個此消彼長的關系,需要設計者在兩者間權衡:增加尾數的位寬會提高表示的精度但是會減少表示的範圍,而增加階碼的位寬雖然擴大了表示的範圍但是會降低表示的精度。因為浮點數規格的定義融入了設計者自身的考慮,所以直到20世紀80年代初,浮點數表示格式還沒有統一标準,不同廠商的計算機内部的浮點數表示格式存在差異。這導緻在不同廠商計算機之間進行含有浮點數的數據傳送或程序移植時,必須進行數據格式的轉換,更為糟糕的是,有時這種數據格式轉換會帶來運算結果不一緻的問題。因此,從20世紀70年代後期開始,IEEE成立委員會着手制定統一的浮點數标準,最終在1985年完成了浮點數标準IEEE 754的制定。該标準的主要起草者是美國加州大學伯克利分校數學系教授William Kahan,他幫助Intel公司設計了8087浮點協處理器,并以此為基礎形成了IEEE 754标準,他本人也因此獲得了1987年的圖靈獎。自IEEE 754标準頒布後,目前幾乎所有的計算機都遵循該标準來表示浮點數。在過去的幾十年間,IEEE 754标準也根據工業界在CPU研發過程中遇到的新需求、實現的新結構,及時進行演進和完善。其中一個比較重要的版本是2008年更新的IEEE 754-2008。該版本中明确了有關融合乘加(Fused Multiply-Add)運算、半精度浮點數等方面的内容。本書僅介紹IEEE 754标準中涉及單精度、雙精度浮點數表示的基本内容,對其他内容感興趣的讀者可查閱相關文獻。

2.3 IEEE 754标準浮點數格式

IEEE 754标準中定義了兩種基本的浮點數格式:32位的單精度格式和64位的雙精度格式:

計算機中的原碼反碼補碼(深入理解計算機中數的表示)1

32位單精度格式中包含1位符号、8位階碼和23位尾數;64位雙精度格式中包含1位符号、11位階碼和52位尾數。兩種格式下基數均隐含為2。

IEEE 754标準中,尾數用原碼表示。由于表示同一個數的時候尾數可以有多種表示,例如可以表示為,也可以表示成,因此需要一個規格化的表示來使得表示唯一。IEEE 754标準中規格化尾數的表示統一為1.xxxx的形式。尾數規格化後第一位總為1,因而可以在尾數中缺省這一位1。隐藏該位後尾數可以多一位表示,精度提高一位。

IEEE 754标準中,階碼是用加偏置常量的移碼表示,但是所用的偏置常量并不是通常n位移碼所用的,而是,因此,單精度和雙精度浮點數的偏置常量分别為127和1023。

我們可以用代碼來模拟一下double的64位雙精度格式:

#include <stdio.h> void floatNumber_1(){ struct FF{ // 小端模式模拟double類型編碼 unsigned l:32; // 剩下的小數位 unsigned m:15; // 剩下的小數位 unsigned k:5; // 取5位小數 unsigned j:11; // 階碼 unsigned i:1; // 符号位 }; union UN { double dd; FF ff; }; UN un; un.dd = -15.75; // -1111.11 printf("%d\n",un.ff.i); // 1 printf("%d\n",un.ff.j); // 1023 3 printf("%d\n",un.ff.k); // 31 也就是二進制的11111 } void floatNumber_2(){ struct FF{ // 小端模式模拟double類型編碼 unsigned l:32; // 剩下的小數位 unsigned m:15; // 剩下的小數位 unsigned k:5; // 取5位小數 unsigned j:11; // 階碼 unsigned i:1; // 符号位 }; union UN { double dd; FF ff; }; UN un; un.ff.i = 1; un.ff.j = 1023 3; un.ff.k = 31; // 二進制的11111 un.ff.m = 0; un.ff.l = 0; printf("%.2lf\n",un.dd); //un.dd = -15.75;// -1111.11 } int main() { floatNumber_1(); floatNumber_2(); while(1); return 0; } /* 1 1026 31 -15.75 */

IEEE 754标準對浮點數的一些情況做了特殊的規定,總的來說可以分為5種情況,主要用階碼進行區分,下表給出了IEEE 754标準中單精度和雙精度不同浮點數的表示。

計算機中的原碼反碼補碼(深入理解計算機中數的表示)2

(1)無窮大:階碼全1尾數全0

引入無窮大是為了在出現浮點計算異常時保證程序能夠繼續執行下去,同時也為程序提供一種檢測錯誤的途徑。 ∞在數值上大于所有有限浮點數,−∞在數值上小于所有有限浮點數。無窮大不僅可以是運算的結果,也可以作為運算的源操作數。當無窮大作為源操作數時,根據IEEE 754标準規定,可以得到無窮大或非數的結果。

(2)非數(NaN):階碼全1尾數非0

非數(NaN)表示一個沒有定義的數。引入非數的目的是檢測非初始化值的使用,而且在計算出現異常時程序能夠繼續執行下去。非數根據尾數的内容又可以分為發信号非數(Signaling NaN)和不發信号非數(Quiet NaN)兩種。如果源操作數是Quiet NaN,則運算結果還是Quiet NaN;如果源操作數是Signaling NaN,則會觸發浮點異常。

(3)規格化非0數:階碼非全0非全1

階碼e的值落在[1, 254](單精度)和[1, 2046](雙精度)範圍内且尾數f是非0值的浮點數是規格化的非0數。其尾數經過規格化處理,最高位的1被省略,因此如果符号位是0,則表示數值為(單精度)和(雙精度);如果符号位是1,則表示數值為(單精度)和(雙精度)。

(4)非規格化非0數:階碼全0尾數非0

在規格化非0數中,能表示的浮點數的最小階值是-126(單精度)和-1022(雙精度),如果浮點數的絕對值小于(單精度)和(雙精度),該如何表示呢?IEEE 754允許特别小的非規格化數,此時階碼為0,尾數的小數點前面的那個1就不再添加了。因此如果符号位是0,則表示數值為(單精度)和(雙精度);如果符号位是1,則表示數值為(單精度)和(雙精度)。非規格化數填補了最小的規格化數和0之間的一段空隙,使得浮點數值可表示的精度進一步提升了很多。

(5)零:階碼全0尾數全0

根據符号位的取值,分為 0和-0。

ref:

https://foxsen.github.io/archbase/運算器設計.html

-End-

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved