計算機的數(shù)值問題有哪些

這篇文章主要講解了“計算機的數(shù)值問題有哪些”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“計算機的數(shù)值問題有哪些”吧!

成都創(chuàng)新互聯(lián)公司主營鶴山網(wǎng)站建設的網(wǎng)絡公司,主營網(wǎng)站建設方案,重慶APP軟件開發(fā),鶴山h5微信小程序開發(fā)搭建,鶴山網(wǎng)站營銷推廣歡迎鶴山等地區(qū)企業(yè)咨詢

一、一些概念

機器數(shù):數(shù)值在計算機內(nèi)部的編碼,也就是實際存儲的 0/1 序列。

真值:機器數(shù)想要表示的實際數(shù)值,可理解為現(xiàn)實生活中我們平常所用的有正負號的數(shù)。

機器數(shù)與真值的對應關(guān)系就是數(shù)值在計算機內(nèi)部的編碼,主要有 4 種:原碼,反碼,補碼,移碼。

原碼

計算機的數(shù)值問題有哪些

原碼由 1 位符號位和數(shù)值部分組成,數(shù)值部分就是真值的絕對值。

特點

  • 與真值的對應關(guān)系直觀

  • 0 的表示不唯一,有 +0(00...000) 和 -0(10...000)。

  • 加減法復雜,需要判斷符號

反碼

計算機的數(shù)值問題有哪些

反碼由 1 位符號位和數(shù)值部分組成。表示一個正數(shù)時同原碼;表示一個負數(shù)時,符號位不變,數(shù)值部分各位求反。

反碼相對于原碼并沒有多大改進提升,現(xiàn)已不用來表示數(shù)據(jù)。

補碼

計算機的數(shù)值問題有哪些

補碼也是由 1 位符號位和數(shù)值部分組成。表示一個整數(shù)時同原碼;表示一個負數(shù)時,符號位不變,數(shù)值部分各位求反,末位加 1。

原碼到補碼快速轉(zhuǎn)換(負數(shù)):符號位不變,從右到左的第一個1不變,其他位取反。 補碼到原碼(負數(shù))轉(zhuǎn)換方法同上,符號位不變,數(shù)值部分各位求反,末位加 1。也就是說符號位不變,從右到左的第一個1不變,其他位取反。

原因:按理說補碼到原碼應為原碼到補碼的逆操作,即減 1 再求反。設補碼為A,則原碼為 ~(A - 1),即11...111 - ( A - 1) = 11...111 - A + 1,也就是~A + 1。 因此 ~A + 1 = ~(A - 1)

一個數(shù)的補碼取負:連同符號位各位求反,末位加1,即從右到左的第一個1不變,其他位取反。

例如 4 位補碼,[x]~補~ = 1011,[-x]~補~ = 0101

特點

  • 0有唯一表示00...000,所以補碼能表示的數(shù)范圍比原碼反碼多1,表示范圍為 -2^n-1^ ~ 2^n-1^-1

  • 加減法符號位能直接參與運算。

  • 現(xiàn)代的計算機整數(shù)基本都采用補碼表示。

移碼

移碼主要用于浮點數(shù)的階碼部分,后面會講浮點數(shù)的階有正負,兩個浮點數(shù)比較時需要比較階碼來対階。為方便比較,將階加上一個偏置常數(shù)使其變成正數(shù),因為加的都是同一個偏置常數(shù),階的差值也是不會改變的。

所以移碼就是數(shù)值本身加上一個偏置常數(shù)得到,偏置常數(shù)一般是2^n-1^,或者2^n-1^-1。

上述都是定點數(shù)的表示方法,定點數(shù)顧名思義,小數(shù)點是約定不動在一個固定位置的。定點數(shù)分為定點小數(shù)和定點整數(shù)。

  • 定點整數(shù)的小數(shù)點固定在數(shù)的最右邊,一般用來表示整數(shù)。

  • 定點小數(shù)的小數(shù)點固定在數(shù)的左邊,一般表示浮點數(shù)的尾數(shù)部分。

而浮點數(shù)的表示類似于科學計數(shù)法,它的指數(shù)部分可以變動,相應的尾數(shù)部分也跟著變化,就像小數(shù)點在浮動一樣,所以叫做浮點數(shù),浮點數(shù)后面再詳解。

二、數(shù)值比較

整數(shù)分為無符號整數(shù)和有符號整數(shù),**給定一個數(shù),在計算機里如何存儲,表示成 0/1 序列是編碼的事,而對這 0/1 序列如何解釋是上層軟件的事情。**如c語言中可解釋為有符號數(shù)和無符號數(shù),而java中只解釋為有符號數(shù)。

數(shù)值比較時,得確定類型才能比較。通常默認為有符號數(shù)相比,若出現(xiàn)無符號數(shù),則按照無符號數(shù)相比。

概念模糊抽象,看下面的經(jīng)典例子來理解: 計算機的數(shù)值問題有哪些

第一個:兩數(shù)按照有符號數(shù)相比,11...111B(-1) < 00...000B(0) 第二個:0U為無符號數(shù),所以兩數(shù)按照無符號數(shù)相比,-1的機器數(shù)為11...111,按照無符號數(shù)解釋為2^32^ -1,這時是大于0的。11...111(2^32^-1) > 00...000(0)

注:括號前的二進制表示為數(shù)值的機器數(shù),通常由補碼表示,括號里面的是c語言對機器數(shù) 按照無符號數(shù)或者有符號數(shù) 解釋出來的數(shù)。

看第二個例子前補充一些知識: 計算機的數(shù)值問題有哪些

判斷一個常量類型時是先將符號“踢開”,只看后面的數(shù)值在哪個區(qū)間,根據(jù)區(qū)間確定類型。

c90 和 C99 是c語言的兩套標準,兩套標準對常量的處理不同,下面的例子以 C90 說明 計算機的數(shù)值問題有哪些

第一個:2147483647為 int 型,兩邊按照有符號數(shù)相比,01...111B(2^31^ - 1) > 10...000B(-2^31^)

第二個:2147483647為 int 型,前者帶有U表示無符號數(shù),按照無符號數(shù)相比,01...111B(231 - 1) < 10...000B(231)

第三個:2147483648為 unsigned int 型,但被強制類型轉(zhuǎn)換為int型,所以按照有符號數(shù)相比,01...111B(2^31 -1^) < 10...000B(-2^31^)

第四個:2147483648為 unsigned int 型,兩數(shù)按照無符號數(shù)相比,01...111B(2^31^ -1) < 10...000B(2^31^)

完全理解上述幾個例子后對數(shù)值比較這一塊應該沒問題了,在此再強調(diào)總結(jié)一番。

一個數(shù)據(jù)怎么存儲成 0/1 序列是編碼的事,怎么解釋這個 0/1 序列是上層軟件的事。

也就是說上述的數(shù)值比較中 2147483648 的機器數(shù)始終是10...000B,2147483647的機器數(shù)始終是01...111B,之所以出現(xiàn)不同的比較結(jié)果是因為 c 語言對它們進行了不同的解釋處理。

有了上面的基礎(chǔ),再來看幾個程序:

計算機的數(shù)值問題有哪些

打印結(jié)果如上圖注釋,原因如下:

x 的機器數(shù)為 11...111,u 的機器數(shù)為 10...0000 所以x按照無符號數(shù)解釋為2^32^ - 1 = 4294967295,按照有符號數(shù)解釋為 -1。 u按照無符號數(shù)解釋為 2^31^,按照有符號數(shù)解釋為 -2^31^

由上也可以看出機器數(shù)為10...000的數(shù),是能表示的最小整數(shù),取負后溢出還是它本身。

計算機的數(shù)值問題有哪些

這是計算數(shù)組元素和的一個函數(shù),按照程序所設想,length 傳入 0 時應該返回 0,但實際上并非如此。這個程序理論上會無限循環(huán),實際運行時會發(fā)生數(shù)組越界導致異常。

理論上無限循環(huán)的原因:len 為無符號數(shù),傳入0時,len - 1 為 -1,機器數(shù)為11...111,按無符號數(shù)解釋為2^32^ -1,是 32 位能表示的最大整數(shù)。

前面說過,有無符號數(shù)參與比較時,兩邊都按照無符號數(shù)相比,所以不管 i 怎么變化,始終小于等于右邊那個最大的值。當 i = 2^32^ -1 時,下一步又會回繞到0;

但實際運行時,肯定不會有那么長的數(shù)組,所以會發(fā)生越界錯誤。

計算機的數(shù)值問題有哪些

此函數(shù)時用來比較兩個字符串str1, str2誰長,用到了庫函數(shù)strlen(),其原型如上。此函數(shù)設想 str1 長時返回 1,否則返回 0;但實際上只有 str1 和 str2 長度相等時會返回 0,其他時候都返回1;

問題就出在函數(shù)strlen()的返回值是size_t,即unsigned int。也就是說比較是按照無符號數(shù)來比較的,無符號數(shù)永遠是大于等于 0 的,所以只有兩個串兒長度相等時會使左邊式子等于 0,其他時候左邊結(jié)果的機器數(shù)中肯定有非 0 位,那么按無符號數(shù)解釋就會大于0,也就返回1了。

改進方法:返回語句改成return strlen(str1) > strlen(str2),直接讓兩個串的長度比較,而不是做減法再與0比較。

這個例子說明調(diào)用庫函數(shù)也要小心,對其的返回類型,參數(shù)類型要有了解,否則可能就會出錯。

三、浮點數(shù)(IEEE 754)

計算機的數(shù)值問題有哪些

IEEE 754浮點數(shù)標準規(guī)定的浮點數(shù)格式如上圖所示,簡要解釋如下:

  • 符號位:1表負,0表正

  • 階碼用移碼表示,是一個定點整數(shù),偏置常數(shù)是2n - 1,所以單精度的偏置常數(shù)位127,雙精度的偏置常數(shù)位1023

  • 尾數(shù)是一個定點小數(shù),實際表示24位有效數(shù)字,隱含了一位 1 ,實際尾數(shù)為1.*****B

表示范圍

32位單精度

計算機的數(shù)值問題有哪些

負數(shù)的表示只不過是符號位發(fā)生變化,所以32位單精度浮點數(shù)能表示的極值如下:

  • 最小正數(shù):2-126

  • 最大整數(shù):(2 - 2-23) * 2127

  • 最大負數(shù):-2-126

  • 最小負數(shù):-(2 - 2-23) * 2127

64位雙精度

64位雙精度浮點數(shù)原理同上,能表示的極值如下

  • 最小正數(shù):2-1022

  • 最大整數(shù):(2 - 2-52) * 21023

  • 最大負數(shù):-2-1022

  • 最小負數(shù):-(2 - 2-52) * 21023

所以IEEE 754 浮點數(shù)能表示的范圍如下面數(shù)軸圖所示:

計算機的數(shù)值問題有哪些

浮點數(shù)每個 2^n-1^~2^n^ 區(qū)間內(nèi)能表示的數(shù)的個數(shù)都是2^23^個(尾數(shù)23位),而且等距。比如 1~2 之間有 2^23^ 個數(shù),2~4 之間也有 2^23 ^個等距的數(shù),所以浮點數(shù)表示的密度并不相等,距離0越近,密度越大。

也就是說并不是每個小數(shù)都能精確表示,當輸入一個不可表示的數(shù)時,機器會將其轉(zhuǎn)換為最近能表示的數(shù)。這也是為什么編寫程序時不要用浮點數(shù)來進行比較,特別是相等的情況,因為你想比較的數(shù)可能無法表示,機器自動給你轉(zhuǎn)換了。

特殊表示

階碼全0尾數(shù)全0

+0 或者 -0,正負看符號位

階碼全1尾數(shù)全0

+∞,-∞,正負看符號位

階碼全1尾數(shù)非0

階碼全1尾數(shù)非0,NaN(Not a Number),不是一個數(shù),0 / 0, 0 * ∞ 等會產(chǎn)生NaN。

階碼全0尾數(shù)非0

從上述的數(shù)軸圖中可以看出-2^-126^ ~ 2^-126^之間的數(shù)是表示不了的,引進非規(guī)格化數(shù)可解決這問題。非規(guī)格化數(shù)的尾數(shù)中的隱含位為0,階碼雖然全0,但階還是-126。如此便在-2^-126^~2^-126^之間添加了2 * 2^23^個數(shù),解決了下溢問題。

同樣,有了上述的基礎(chǔ)知識,來看一些例子: 計算機的數(shù)值問題有哪些

這幾個題都很簡單,注意幾點就行:

  • 精度大的轉(zhuǎn)換成精度小的可能會出問題,精度小的轉(zhuǎn)換成精度大的不會有問題。

  • 浮點數(shù)取負直接變符號位就可。

最后一個是浮點數(shù)的加減運算問題,后面詳解,在這可以舉個例子簡單理解下:當 d 很大 f 很小時,d + f 得到的結(jié)果就等于 d, 舍去了f,所以左邊等于 0 ,右邊等于 f,兩邊不等。

四、數(shù)值運算

按位運算和邏輯運算

這兩種運算比較簡單,只是要區(qū)分一下概念。

按位運算恰如其名,是對數(shù)值的位進行與或非運算。

邏輯運算的操作數(shù)只有 true 和 false,對數(shù)值的處理為非零即真。

左移右移

移位分為邏輯移位和算數(shù)移位:

  • 邏輯移位:不考慮符號位,左移時高位移出,低位補0;右移時低位移出,高位補0

  • 算術(shù)移位:考慮符號位,左移時高位移出,低位補0;右移時低位移出,高位補符號位;

c語言中編譯器進行移位運算和CPU進行移位運算是不一樣的:

  • 編譯器:進行實際移位,比如移動w位,實際也移動w位

  • CPU:移動 w % k ,w為所移位數(shù),k為數(shù)據(jù)類型的位數(shù)

看下面程序幫助理解,打印結(jié)果已注釋在后面 計算機的數(shù)值問題有哪些

位擴展位截斷

擴展分為 0 擴展和符號擴展,數(shù)據(jù)轉(zhuǎn)換時,短數(shù)向長數(shù)轉(zhuǎn)換時需要位擴展。

0擴展用于無符號數(shù),在原來的數(shù)前面添足夠的0即可。

符號擴展用于有符號數(shù),在原來的數(shù)前面添足夠的符號位即可。

位截斷,長數(shù)向短數(shù)轉(zhuǎn)化時會發(fā)生截斷,規(guī)則比較粗暴簡單,直接“砍掉”高位,留下低位即可。

長數(shù)的表示范圍肯定大于短數(shù),所以截斷一個數(shù)可能會改變原來的值??聪旅嬉粋€例子: 計算機的數(shù)值問題有哪些

經(jīng)過截斷再擴展后 32768 變成了 -32768,所以再截斷時要注意溢出問題。


計算機里整數(shù)浮點數(shù)的加減乘除運算的實際過程都很復雜,內(nèi)容很多,建議直接看唐朔風的計算機組成原理第六章,數(shù)字邏輯相關(guān)書籍中加法器,乘法器等的電路實現(xiàn)。深入理解計算機系統(tǒng)對各種數(shù)值算法的理論推導。公眾號內(nèi)回復電子書即可獲得相應書籍。下面就只說說其中我認為比較重要需要的一些東西。

加減運算

現(xiàn)代計算機里面整數(shù)都可以看做是用補碼表示的,統(tǒng)一了加減法,符號位也能和數(shù)值部分一起進行計算。

不論是無符號數(shù)還是有符號數(shù),都先按照實際的機器數(shù)做運算,得到的結(jié)果再解釋成相應的無符號數(shù)或有符號數(shù)。

整個計算機的運算系統(tǒng)都是采用模運算,得出的結(jié)果如果超出計算機表示的位數(shù),會直接丟掉高位。

例如若兩個數(shù)為a, b,對應的機器數(shù)為A, B,則a + b 相應操作為 A + B,a - b 為A + ~ B + 1。再對計算得到機器數(shù)解釋成最終結(jié)果。

乘除運算

乘法主要需要考慮溢出問題,n 位數(shù)乘 n 位數(shù),結(jié)果可能需要2n位來表示。c語言中截直接斷成 n 位來實現(xiàn)(來自深入理解計算機系統(tǒng)),但經(jīng)過試驗結(jié)果似乎會自動擴展。

只要結(jié)果在你機器的表示范圍內(nèi)就會自動擴展,比如兩個 short 型的數(shù)相乘結(jié)果會自動擴展成 32 位來正確表示結(jié)果,除非限定結(jié)果還是個 short 型,才會截斷。

整數(shù)除法一般沒有溢出問題,因為商的絕對值不會大于被除數(shù)的絕對值。

除了一種情況,有符號數(shù)中最小數(shù)除以-1,例如 int 型的情況:-2147483648 / -1 便會溢出,結(jié)果還是 -2147483648 本身。

在這說點 c 里面一些有趣的東西,可以算是bug吧。上述說的有符號數(shù)中的最小數(shù),即機器數(shù)為10...000的數(shù)(設為s)取負后還是它本身,這是沒問題的,機器數(shù)也的確是相同的。所以按理說 s = -s。這在32位int型,64位long long的情況下成立,但是在short情況下不成立。所以 c 里面關(guān)于數(shù)值的東西有許多奇奇怪怪的東西,諸位感興趣可以去嘗試。

常量乘除

乘除法運算所花的時間遠遠多于移位加減運算的時間,因此,編譯器處理變量與常量乘除時會以移位,加法,減法的組合運算來代替乘除法。

來看一個具體例題:x為一整形變量,現(xiàn)要計算55 * x,給出一種計算表達式使得所用的時鐘周期最少。 計算機的數(shù)值問題有哪些

題目很簡單,主要是想說明怎么轉(zhuǎn)換。

乘以 2^n^ 相當于左移 n 位,除以 2^n^ 相當于右移 n 位。 **左移需要注意高位的溢出問題,而右移則需要注意舍入問題。一般的舍入規(guī)則是向0舍入,但用移位來實現(xiàn)除法是向下舍入的。**對于正數(shù)來說沒什么問題,向下舍入就是向0舍入。但是負數(shù)就有問題了,向下舍入并不是向0舍入,需要校正。

為什么移位來實現(xiàn)除法是向下舍入的呢,正數(shù)應該很好理解,右移之后丟掉移出的小數(shù)部分,數(shù)值自然變小了。如果是負數(shù),右移之后丟掉小數(shù)部分數(shù)值不應該變大嗎?但別忘了負數(shù)在計算機里由補碼表示,它跟真值對應的關(guān)系是要求反的,所以換成真值后會發(fā)現(xiàn)數(shù)值依然是變小的。

來看一個例子理解向下舍入,應該會更清楚 計算機的數(shù)值問題有哪些

如何校正呢? 既然負數(shù)也是向下舍入,那么在它移位之前先給它加上一個偏移量讓它變大點,那么移位后舍入不就正確了。

如果右移n位,這個偏移量就是2^n^-1,原來是 x / 2^n^,現(xiàn)在是(x + 2^n^ - 1) / 2n = x / 2^n^ + (2^n^-1 / 2^n^);相當于加了一個"極限小數(shù)"來校正。

這個數(shù)可以在十進制下來理解,比如移動一位也就是一位小數(shù)的情況下,-2.1,-2.9都要舍入到-2,應該怎么操作呢?將兩個數(shù)都加上一個0.9就行了,這里0.9就是十進制一位情況下的一個極限小數(shù),換成二進制同理,二進制 n 位的一個"極限小數(shù)"就是2^n^-1 。

浮點數(shù)運算

加減法

1、対階

只有階數(shù)相等,尾數(shù)才能直接相加減。 対階原則:小階對齊大階,階小的尾數(shù)右移,右移尾數(shù)為階差。

注: 右移時注意隱含位 1 也要一起參與移位,為保證精度,低位移出的位不要丟掉,后續(xù)參與尾數(shù)加減。

2、尾數(shù)加減

尾數(shù)是由定點原碼小數(shù)表示,這里沒有符號位,所以加減就是普通的二進制加減法。這里注意隱含位和対階時移出的附加位也要參與運算。

3、規(guī)格化

上述尾數(shù)加減后得到結(jié)果可能五花八門,千奇百怪,需要規(guī)格化變成 IEEE 754 的標準形式。**簡單說來就是把尾數(shù)變成1. **B的形式,然后相應的調(diào)整階碼。小數(shù)點的位置與階碼息息相關(guān),小數(shù)點浮動了,階碼當然也要相應變化。

4、結(jié)果舍入

対階和尾數(shù)規(guī)格化的時都可能右移,為保證精度,會將移出的位保留下來參與中間運算,得出最終結(jié)果后再舍入。IEEE 754規(guī)定至少保留 2 位,緊跟在尾數(shù)右邊的叫做保護位(guard),保護位右邊的叫做舍入位(round),為提高精度,舍入位右邊還有一位粘位(sticky)。只要粘位右邊有任何的非0數(shù)就置1,否則置0。

5、階碼溢出判斷

結(jié)果的階碼全 1 表上溢,產(chǎn)生異常或者結(jié)果置為∞。 結(jié)果的階碼全 0 表下溢,產(chǎn)生異?;蛘呓Y(jié)果置0

這就能解釋前面為什么 (d + f ) - d 不一定等于 f ,d 如果很大,f 很小,対階時f 看齊d,尾數(shù)可能一直右移導致有效位沒有了變成了全0,再進行尾數(shù)加減時 d 值不變。所以左邊等于0,右邊等于 f,兩者不等。

乘除法

浮點數(shù)乘法運算過程類似加減法,主要區(qū)別在于乘除法不用対階,其他過程基本一樣。也好理解,就像我們平時用科學計數(shù)法做算數(shù)時,加減法那肯定是需要指數(shù)相等,尾數(shù)才能相加減;而乘除法時可以直接尾數(shù)與尾數(shù)運算,指數(shù)與指數(shù)運算,一個道理。

感謝各位的閱讀,以上就是“計算機的數(shù)值問題有哪些”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對計算機的數(shù)值問題有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

當前名稱:計算機的數(shù)值問題有哪些
URL分享:http://www.muchs.cn/article48/ippiep.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄小程序開發(fā)、搜索引擎優(yōu)化、網(wǎng)站改版、定制開發(fā)、云服務器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設