了解JavaScript的Number類型

許多的語言都有好幾種不同的數字類型,比如C++,分別有int,float和double,外加各種變種long int, unsigned等等,實在是繁多,不過,JavaScript中,就只有一種數字類型——number
比如,我們在瀏覽器的console中敲下下列代碼.

實際上,所有的數字類型,在JavaScript中,都是雙倍精度的浮點數類型,就和前面提到的C++的double一樣.按照標準,就是每一個數字,都是使用64位(8字節)來存儲.
要理解JavaScript中數字存儲特性,我們首先需要復習一下,在計算機中,是如何使用二進制來保存浮點數的.

浮點數的二進制表示

現今計算機浮點數的表示,都是采用了IEEE754標準,一個由Intel主導開發的標準,有興趣的同學可以了解一下上個世紀80年代的各種不同公司對于浮點數的表示,不過現在都已經按照標準來進行處理了.
任意一個浮點數都可以表示成如下的形式.


  • 符號位(sign) (-1)^s表示的是符號位,當s=0時,V是正數,當s=1時,v為負數.
  • 有效位(significand) M表示有效數字,范圍是[1,2)或者是[0,1)
  • 指數(exponent) 2^E表示指數位.E的作用是對浮點數加權。
    這種表示方式非常適合用于處理非常大或者非常接近0的數字.
    了解的公式的表示,接下來,我們就可以對浮點數的位按照上述的三個變量進行劃分,分別對其進行編碼:
  • 1個單獨的符號位s用于編碼符號s.
  • k位階碼字段,用以編碼指數E.
  • n位冪字段,用以編碼尾數M.

下面,我們用C語言中的單精度浮點數(float)以及雙精度浮點數(double)進行說明.
單精度浮點數使用32bit來進行存儲,分別s=1, k=8以及n=23.其存儲結構如下圖所示



32位的存儲空間被分割成了三個部分,也就是對應上面所說的s,k以及n.
雙精度浮點數則是使用32位進行存儲,分別是s=1, k=11, n=52.



為了簡單起見,接下來使用單精度浮點數來進行說明.
單精度浮點數一共表示4種類型的數值,分別是:
  • 規范化(Normalized)


  • 非規范化(Denormalized)


  • 無窮(Infinity)


  • 非數字(NaN)

    嚴格來說,Infinity以及NaN屬于同一類,因為他們的k相同,都是1,只是n上面的值不一樣,一個是全是0,另外一個全是1.
    具體上就不展開講了,以后會另外開一篇新的文章來進行詳細講述計算機底層對于浮點數的存取.現在仍舊是Javascript的主場.我們要知道一點就是,根據浮點數的二進制表示形式,有一部分值是無法完全使用二進制準確表示的.就好比1/3這個值,在十進制上面,我們只能不斷的用0.3333333來無限循環表示,但是計算機表示一個浮點數的位是有限的,所以需要對多余的位進行截取,這一點就是誤差的來源.
    知道了計算機中浮點數的二進制表示,我們都不難理解一些問題了,比如,JavaScript中的數字范圍是從-2^532^53.因此,JavaScript中的數字是非常適合用以做數學運算的,因為范圍非常的大,不容易導致溢出的問題.

位運算操作

許多的數學運算,都是以浮點數的形式直接計算的,比如:

    0.1 * 1.9 // 0.19
    -99 + 100 // 1
    21 - 12.3 //8.7

但是,對于位運算則是比較特別,對于位運算,JavaScript會首先把浮點數轉換成32位的整型來進行處理,而不是直接對浮點型進行操作.準確的來說,是轉換成32位,大端序, 補碼的整型.(這里涉及到比較多操作系統的概念).
舉個例子

    8 | 1 // 9

這個看起來很簡單的操作,8與1進行或運算,實際上經歷了好幾步的運算,才得到結果9,并不是一下子得出結果的.
正如前面所說,8和1一開始是64位的double,但是,他們在位運算的時候,會被轉換成32位的整型,對于數字8,則會轉換成00000000000000000000000000001000,我們可以驗證一下

    (8).toString(2); // "1000"

同理,1則會轉換成00000000000000000000000000000001,把這兩個數分別按位進行或運算

00000000000000000000000000001000
00000000000000000000000000000001
--------------------------------
00000000000000000000000000001001

就會得到1001這一個數字,我們使用parseInt("1001", 2)對其進行轉換,結果就是9.
所有的位運算,都是按照上面所說的這一種方式來進行處理的.

  • 把操作數轉換成32位整型
  • 按位進行位運算
  • 把得到的結果轉換會JavaScript浮點型屬性.

因為這些轉換都依賴于JavaScript的引擎,所以有部分引擎經過優化,就會把部分算術運算的操作數用整型來存儲,從而避免了一些無謂的轉換.

浮點數運算,可靠嗎?

說了這么多,什么64位雙精度浮點數,計算機儲存的方式等等,那么,JavaScript中的浮點數運算,可靠嗎?先來看一個例子:


為什么上面得出的結果不是0.3,而是后面跟了一大堆0,后面還有個4?前面我們談到了浮點數的二進制存儲方式,我們知道,計算機僅僅可以使用二進制無限的接近部分浮點數,但是無法完全接近,即便64位浮點數以及可以很高精度的接近了,但是仍舊會產生誤差.浮點數的算術運算僅僅可以產生一個近似值,這個近似值接近于真實值.
有一個比較悲觀的事實就是,這些錯誤會隨著一系列的計算而累加起來,從而導致偏差越來越多,結果越來越不精確.
舉個例子,我們都知道
(x + y) + z = x + (y + z)
但是,這一點在計算機中,可不一定會成立.

在部分計算機無法精確表達的浮點數產生的時候,就會導致誤差的產生.
這種誤差短期內還好,但是長期來說,是不可忍受的,假設是銀行或者金融機構使用node作為服務端進行處理,日積月累,就會發生許多的問題.
浮點數運算是不準確的,那么我們應該怎么避免這個問題呢?
一個很簡單的方法,就是避免浮點數的運算,把所有的運算都使用整型來進行.因為整型的運算是沒有省略近似的.例如,上面那個例子,我們換成這個

如果使用整型來進行算術運算,就不會產生上面的問題了,從而也保證了運算的精確性.

總結

  • Javascript的數字類型是雙精度浮點型.
  • 在Javascript中,整型是double的一個子集,而不是一個獨立的數據類型.
  • Javascript在進行位運算的時候會把數字轉換成32位整型來進行處理.
  • 浮點數運算是不準確的,擁有許多的局限性.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容