了解JavaScript的Number類型

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

實(shí)際上,所有的數(shù)字類型,在JavaScript中,都是雙倍精度的浮點(diǎn)數(shù)類型,就和前面提到的C++的double一樣.按照標(biāo)準(zhǔn),就是每一個(gè)數(shù)字,都是使用64位(8字節(jié))來存儲(chǔ).
要理解JavaScript中數(shù)字存儲(chǔ)特性,我們首先需要復(fù)習(xí)一下,在計(jì)算機(jī)中,是如何使用二進(jìn)制來保存浮點(diǎn)數(shù)的.

浮點(diǎn)數(shù)的二進(jìn)制表示

現(xiàn)今計(jì)算機(jī)浮點(diǎn)數(shù)的表示,都是采用了IEEE754標(biāo)準(zhǔn),一個(gè)由Intel主導(dǎo)開發(fā)的標(biāo)準(zhǔn),有興趣的同學(xué)可以了解一下上個(gè)世紀(jì)80年代的各種不同公司對(duì)于浮點(diǎn)數(shù)的表示,不過現(xiàn)在都已經(jīng)按照標(biāo)準(zhǔn)來進(jìn)行處理了.
任意一個(gè)浮點(diǎn)數(shù)都可以表示成如下的形式.


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

下面,我們用C語言中的單精度浮點(diǎn)數(shù)(float)以及雙精度浮點(diǎn)數(shù)(double)進(jìn)行說明.
單精度浮點(diǎn)數(shù)使用32bit來進(jìn)行存儲(chǔ),分別s=1, k=8以及n=23.其存儲(chǔ)結(jié)構(gòu)如下圖所示



32位的存儲(chǔ)空間被分割成了三個(gè)部分,也就是對(duì)應(yīng)上面所說的s,k以及n.
雙精度浮點(diǎn)數(shù)則是使用32位進(jìn)行存儲(chǔ),分別是s=1, k=11, n=52.



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


  • 非規(guī)范化(Denormalized)


  • 無窮(Infinity)


  • 非數(shù)字(NaN)

    嚴(yán)格來說,Infinity以及NaN屬于同一類,因?yàn)樗麄兊膋相同,都是1,只是n上面的值不一樣,一個(gè)是全是0,另外一個(gè)全是1.
    具體上就不展開講了,以后會(huì)另外開一篇新的文章來進(jìn)行詳細(xì)講述計(jì)算機(jī)底層對(duì)于浮點(diǎn)數(shù)的存取.現(xiàn)在仍舊是Javascript的主場(chǎng).我們要知道一點(diǎn)就是,根據(jù)浮點(diǎn)數(shù)的二進(jìn)制表示形式,有一部分值是無法完全使用二進(jìn)制準(zhǔn)確表示的.就好比1/3這個(gè)值,在十進(jìn)制上面,我們只能不斷的用0.3333333來無限循環(huán)表示,但是計(jì)算機(jī)表示一個(gè)浮點(diǎn)數(shù)的位是有限的,所以需要對(duì)多余的位進(jìn)行截取,這一點(diǎn)就是誤差的來源.
    知道了計(jì)算機(jī)中浮點(diǎn)數(shù)的二進(jìn)制表示,我們都不難理解一些問題了,比如,JavaScript中的數(shù)字范圍是從-2^532^53.因此,JavaScript中的數(shù)字是非常適合用以做數(shù)學(xué)運(yùn)算的,因?yàn)榉秶浅5拇?不容易導(dǎo)致溢出的問題.

位運(yùn)算操作

許多的數(shù)學(xué)運(yùn)算,都是以浮點(diǎn)數(shù)的形式直接計(jì)算的,比如:

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

但是,對(duì)于位運(yùn)算則是比較特別,對(duì)于位運(yùn)算,JavaScript會(huì)首先把浮點(diǎn)數(shù)轉(zhuǎn)換成32位的整型來進(jìn)行處理,而不是直接對(duì)浮點(diǎn)型進(jìn)行操作.準(zhǔn)確的來說,是轉(zhuǎn)換成32位,大端序, 補(bǔ)碼的整型.(這里涉及到比較多操作系統(tǒng)的概念).
舉個(gè)例子

    8 | 1 // 9

這個(gè)看起來很簡(jiǎn)單的操作,8與1進(jìn)行或運(yùn)算,實(shí)際上經(jīng)歷了好幾步的運(yùn)算,才得到結(jié)果9,并不是一下子得出結(jié)果的.
正如前面所說,8和1一開始是64位的double,但是,他們?cè)谖贿\(yùn)算的時(shí)候,會(huì)被轉(zhuǎn)換成32位的整型,對(duì)于數(shù)字8,則會(huì)轉(zhuǎn)換成00000000000000000000000000001000,我們可以驗(yàn)證一下

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

同理,1則會(huì)轉(zhuǎn)換成00000000000000000000000000000001,把這兩個(gè)數(shù)分別按位進(jìn)行或運(yùn)算

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

就會(huì)得到1001這一個(gè)數(shù)字,我們使用parseInt("1001", 2)對(duì)其進(jìn)行轉(zhuǎn)換,結(jié)果就是9.
所有的位運(yùn)算,都是按照上面所說的這一種方式來進(jìn)行處理的.

  • 把操作數(shù)轉(zhuǎn)換成32位整型
  • 按位進(jìn)行位運(yùn)算
  • 把得到的結(jié)果轉(zhuǎn)換會(huì)JavaScript浮點(diǎn)型屬性.

因?yàn)檫@些轉(zhuǎn)換都依賴于JavaScript的引擎,所以有部分引擎經(jīng)過優(yōu)化,就會(huì)把部分算術(shù)運(yùn)算的操作數(shù)用整型來存儲(chǔ),從而避免了一些無謂的轉(zhuǎn)換.

浮點(diǎn)數(shù)運(yùn)算,可靠嗎?

說了這么多,什么64位雙精度浮點(diǎn)數(shù),計(jì)算機(jī)儲(chǔ)存的方式等等,那么,JavaScript中的浮點(diǎn)數(shù)運(yùn)算,可靠嗎?先來看一個(gè)例子:


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

在部分計(jì)算機(jī)無法精確表達(dá)的浮點(diǎn)數(shù)產(chǎn)生的時(shí)候,就會(huì)導(dǎo)致誤差的產(chǎn)生.
這種誤差短期內(nèi)還好,但是長(zhǎng)期來說,是不可忍受的,假設(shè)是銀行或者金融機(jī)構(gòu)使用node作為服務(wù)端進(jìn)行處理,日積月累,就會(huì)發(fā)生許多的問題.
浮點(diǎn)數(shù)運(yùn)算是不準(zhǔn)確的,那么我們應(yīng)該怎么避免這個(gè)問題呢?
一個(gè)很簡(jiǎn)單的方法,就是避免浮點(diǎn)數(shù)的運(yùn)算,把所有的運(yùn)算都使用整型來進(jìn)行.因?yàn)檎偷倪\(yùn)算是沒有省略近似的.例如,上面那個(gè)例子,我們換成這個(gè)

如果使用整型來進(jìn)行算術(shù)運(yùn)算,就不會(huì)產(chǎn)生上面的問題了,從而也保證了運(yùn)算的精確性.

總結(jié)

  • Javascript的數(shù)字類型是雙精度浮點(diǎn)型.
  • 在Javascript中,整型是double的一個(gè)子集,而不是一個(gè)獨(dú)立的數(shù)據(jù)類型.
  • Javascript在進(jìn)行位運(yùn)算的時(shí)候會(huì)把數(shù)字轉(zhuǎn)換成32位整型來進(jìn)行處理.
  • 浮點(diǎn)數(shù)運(yùn)算是不準(zhǔn)確的,擁有許多的局限性.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末按摘,一起剝皮案震驚了整個(gè)濱河市假残,隨后出現(xiàn)的幾起案子痴昧,更是在濱河造成了極大的恐慌从铲,老刑警劉巖酵颁,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衙熔,死亡現(xiàn)場(chǎng)離奇詭異登颓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)红氯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門框咙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人痢甘,你說我怎么就攤上這事喇嘱。” “怎么了塞栅?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵者铜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)作烟,這世上最難降的妖魔是什么愉粤? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拿撩,結(jié)果婚禮上衣厘,老公的妹妹穿的比我還像新娘。我一直安慰自己压恒,他們只是感情好影暴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著探赫,像睡著了一般型宙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上期吓,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天早歇,我揣著相機(jī)與錄音,去河邊找鬼讨勤。 笑死箭跳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潭千。 我是一名探鬼主播谱姓,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼刨晴!你這毒婦竟也來了屉来?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤狈癞,失蹤者是張志新(化名)和其女友劉穎茄靠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝶桶,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慨绳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了真竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脐雪。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恢共,靈堂內(nèi)的尸體忽然破棺而出战秋,到底是詐尸還是另有隱情,我是刑警寧澤讨韭,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布脂信,位于F島的核電站癣蟋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏狰闪。R本人自食惡果不足惜梢薪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尝哆。 院中可真熱鬧,春花似錦甜攀、人聲如沸秋泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恒序。三九已至,卻和暖如春谁撼,著一層夾襖步出監(jiān)牢的瞬間歧胁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工厉碟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喊巍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓箍鼓,卻偏偏與公主長(zhǎng)得像崭参,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子款咖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容