開始本章之前我先提個問題:“如果一個整數(shù)的絕對值等于它自己,那么這個數(shù)是幾?”如果你回答是 0 和 所有正數(shù),那么請你耐心讀完這篇文章吧。
本章是我『代碼之謎』系列的第二篇,前一篇『代碼之謎 - 開篇/前言/序』簡單介紹了計算機與數(shù)學的不同。
數(shù)學中有許多復雜深刻的矛盾,數(shù)學家的工作就是解釋或者反駁這些矛盾, 例如有限與無限、連續(xù)與離散、存在與構(gòu)造、邏輯與直觀、具體與抽象、概念與計算等等。
在本章中,我們把目標縮小,主要討論內(nèi)容
終于到主題了,也許你很想知道“負數(shù)的絕對值可能等于自己嗎?”,也就是 “如果x等于-x,那么x有幾個解?”按照我一貫的作風,我是不會輕易告訴你答案的。 《編程珠璣》記載,作者告訴了他同事一個結(jié)果,而不是方法,最后追悔莫及。 所以,我在這里要告訴你方法,而不是告訴你答案。
告訴你答案之前,首先得回答個問題:“整數(shù)(8bit)的表示范圍是多少?”,(也許你已經(jīng)把教科書的知識背下來了,是 -2^7 到 2^7 - 1,也就是 -128 到 +127,現(xiàn)在的計算機科學都快成為文科了 ^_^ )。
如果你不知道也沒關(guān)系,至少你知道 8bit 可以表示的整數(shù)個數(shù)是 2^8 個,這個數(shù)等于多少無所謂,但是,它一定是個偶數(shù)(256)。
那么這里就有一個很有意思的問題了,0既不是正數(shù)也不是負數(shù),把0去掉的話,整數(shù)的個數(shù)就是奇數(shù)了,整數(shù)還剩 255 個。 奇數(shù)個整數(shù)不可能平均分成兩部分(正數(shù)和負數(shù)),要么負數(shù)多一個,要么正數(shù)多一個。事實就是,負數(shù)比正數(shù)多一個,最小的負數(shù)是 -128, 最大的整數(shù)是 127。
現(xiàn)在的問題是, -128 的絕對值是多少呢? -(-128)等于多少呢?是溢出呢,還是等于它自己呢?也許計算機課本沒有告訴你,?整數(shù)是不會出現(xiàn)溢出異常的,整數(shù)的溢出被認為是正常的舍棄(其實只要很合理)。整數(shù)只有被0除才會異常,而浮點數(shù),即使被0除也不會拋出異常。 浮點數(shù)除0的操作將放在本系列浮點數(shù)篇討論。
絕對值等于自己的數(shù)有兩個,0 和最小的負數(shù)。
你可能要像香港電影里女主角那樣歇斯底里的大喊“絕對值怎么可能是負數(shù)呢? 不可能,我不信,我不信…”
忘掉你那可憐的數(shù)學知識吧,“發(fā)生這種事,大家都不想的。感情的事呢,是不能強求的。所謂吉人自有天相,做人呢,最要緊的就是開心…”跑題了,趕緊回來。
在經(jīng)典數(shù)學(非皮亞諾算術(shù)系統(tǒng),皮亞諾絕對是歐幾里德的鐵桿粉絲,要不怎么會有如此天才的構(gòu)想,這個以后會給大家普及)中,絕對值定義為:“從原點到點A的距離,稱為A的絕對值,它是一個非負數(shù)”。 既然講到了距離,不妨劇透一下(本系列“邏輯篇”會涉及到),兩個數(shù)的大小在數(shù)學中如何定義,“距離數(shù)軸原點的距離遠近”,計算機中大小如何定義的呢?給大家留個作業(yè)吧(別告訴我是設計編程語言或者設計電腦的科學家規(guī)定的,計算機科學絕對不是文科)。
計算機中沒有數(shù)軸,絕對值是如何定義的呢?看看java、C、Python的源碼(感謝那些開源大牛),和咱們學的小學數(shù)學一樣。
abs(x) := (x >= 0) ? x : -x
翻譯過來就是,x的絕對值定義為:正數(shù)和0的絕對值等于它自己,負數(shù)的絕對值等于-x。(這里使用的是-x,而沒有用0-x,因為在浮點數(shù)中,這兩者是有區(qū)別的。)
那么 -x 是如何計算的呢??計算是數(shù)學概念,在計算機中,我們應該說 -x是如何求值的呢?還得回到源碼,我只看了linux中關(guān)于C的源碼,如果你看過其它語言源碼發(fā)現(xiàn)和我說的不同,請聯(lián)系我。 學過計算機原理的都知道,負數(shù)在計算機中以補碼形式存儲,計算補碼的方式和取反操作類似。
符號位不變,其它位取反,最后加一。
比如 -5
原碼: 1000,0101
其它位取反: 1111,1010
加一: 1111,1011
當我們求它的絕對值時如何操作呢
補碼: 1111,1011 這是-5在計算機中的表示
各位取反: 0000,0100
加一: 0000,0101 此時結(jié)果為+5
現(xiàn)在我們回到最小的負數(shù)問題,最小的負數(shù)在計算機中表示為 1000,000,下面我們對這個數(shù)操作
補碼: 1000,0000
各位取反: 0111,1111
加一: 1000,0000
神奇嗎,尼瑪,居然又回到自己了。
更多建議: