摘要:數(shù)字?jǐn)?shù)字都是浮點(diǎn)數(shù),按照標(biāo)準(zhǔn)進(jìn)行存儲(chǔ)。因此,只有偶數(shù)可以在范圍內(nèi)表示。但只有超過指數(shù)的上限才稱為中的溢出。結(jié)論在這篇博文中,我們研究了如何將其浮點(diǎn)數(shù)轉(zhuǎn)換為位。
JavaScript中的所有數(shù)字都是浮點(diǎn)數(shù)。這篇博客文章解釋了這些浮點(diǎn)數(shù)如何在64位二進(jìn)制內(nèi)部表示。由于特別考慮,本文中的數(shù)字將用整數(shù)表示,以便在閱讀本文后,您將了解在以下交互中會(huì)發(fā)生什么:
(譯者注:浮點(diǎn)數(shù)并不一定等于小數(shù),定點(diǎn)數(shù)也并不一定就是整數(shù)。所謂浮點(diǎn)數(shù)就是小數(shù)點(diǎn)在邏輯上是不固定的,而定點(diǎn)數(shù)只能表示小數(shù)點(diǎn)固定的數(shù)值,具用浮點(diǎn)數(shù)或定點(diǎn)數(shù)表示某哪一種數(shù)要看用戶賦予了這個(gè)數(shù)的意義是什么。)
> 9007199254740992 + 1 9007199254740992 > 9007199254740992 + 2 9007199254740994JavaScript數(shù)字
JavaScript數(shù)字都是浮點(diǎn)數(shù),按照IEEE 754 standard標(biāo)準(zhǔn)進(jìn)行存儲(chǔ)。該標(biāo)準(zhǔn)有幾種格式。 JavaScript使用binary64或雙精度。正如前面的名稱所表示的,數(shù)字以二進(jìn)制格式存儲(chǔ)在64位中。這些比特分配如下:分?jǐn)?shù)占據(jù)比特0到51,指數(shù)占據(jù)比特52到62,符號占用比特63。
| sign (1 bit)
63
| exponent (11 bit)
62
52
| fraction (52 bit)
51
|
這些組件的工作原理如下:如果符號位為0,則數(shù)字為正數(shù),否則為負(fù)數(shù)。粗略地說,分?jǐn)?shù)包含數(shù)字的值,而指數(shù)表示該點(diǎn)的位置。在下面,我們經(jīng)常使用二進(jìn)制數(shù)字,這在浮點(diǎn)數(shù)方面有點(diǎn)不尋常。二進(jìn)制數(shù)字將以前綴??百分比符號(%)標(biāo)記。雖然JavaScript數(shù)字以二進(jìn)制格式存儲(chǔ),但默認(rèn)輸出為十進(jìn)制[1]。在示例中,我們通常會(huì)使用該默認(rèn)值。
分?jǐn)?shù)以下是表示非負(fù)浮點(diǎn)數(shù)的一種方法:有效數(shù)(或尾數(shù))包含數(shù)字,作為自然數(shù),指數(shù)指定點(diǎn)的左邊(負(fù)指數(shù))或右邊(正指數(shù))的點(diǎn)數(shù)應(yīng)該轉(zhuǎn)移。 JavaScript數(shù)字使用有理數(shù)作為有效數(shù):1._f_其中_f_是52位小數(shù)。忽略符號,數(shù)字是有效數(shù)字乘以2_p_,其中_p_是指數(shù)(在稍后將解釋的轉(zhuǎn)換之后)。
比如:
| f = %101, p = 2 | Number: %1.101 × 22 = %110.1 |
| f = %101, p = ?2 | Number: %1.101 × 2?2 = %0.01101 |
| f = 0, p = 0 | Number: %1.0 × 20 = %1 |
整數(shù)的編碼有多少位?有效數(shù)字有53個(gè)數(shù)字,一個(gè)在點(diǎn)之前,52個(gè)點(diǎn)。用_p_ = 52,我們有一個(gè)53位的自然數(shù)。唯一的問題是最高位始終為1.也就是說,我們沒有全部位可供我們隨意使用。分兩步去除這個(gè)限制。首先,如果你需要一個(gè)最高位為0的53位數(shù),然后是1,那么你設(shè)置_p_ = 51.分?jǐn)?shù)的最低位成為該點(diǎn)之后的第一個(gè)數(shù)字,整數(shù)為0。依此類推,直到你處于編碼數(shù)字1的_p_ = 0和_f_ = 0。
| | 52 | 51 | 50 | ... | 1 | 0 | (bits) |
| p=52 | 1 | f51 | f50 | ... | f1 | f0 | |
| p=51 | 0 | 1 | f51 | ... | f2 | f1 | f0=0 |
| | ... |
| p=0 | 0 | 0 | 0 | ... | 0 | 1 | f51=0, etc. |
其次,對于全部53位,我們?nèi)匀恍枰硎玖恪H绾巫龅竭@一點(diǎn)在下一節(jié)中解釋。請注意,由于符號是多帶帶存儲(chǔ)的,因此整數(shù)的幅度(絕對值)為53位。
指數(shù)指數(shù)的長度是11位,這意味著它的最低值是0,最高值是2047(211-1)。為了支持負(fù)指數(shù),使用所謂的偏移二進(jìn)制編碼:1023是零,所有較低數(shù)字都是負(fù)數(shù),所有較高數(shù)字都是正數(shù)。這意味著你從指數(shù)中減去1023將其轉(zhuǎn)換為正常數(shù)字。因此,我們以前使用的變量_p_等于_e_-1023,并且有效數(shù)字乘以2_e_-1023。
偏移量二進(jìn)制編碼中的一些數(shù)字:
%00000000000 0 → ?1023 (lowest number) %01111111111 1023 → 0 %11111111111 2047 → 1024 (highest number) %10000000000 1024 → 1 %01111111110 1022 → ?1
你倒置它的位并減1就能將一個(gè)數(shù)變?yōu)樨?fù)數(shù)了。
特殊的指數(shù)兩個(gè)指數(shù)值是保留的:最低的一個(gè)(0)和最高的一個(gè)(2047)。 2047的指數(shù)用于無窮大和NaN(非數(shù)字)值[2]。 IEEE 754標(biāo)準(zhǔn)有許多NaN值,但JavaScript都將它們表示為單個(gè)值NaN。指數(shù)0用于兩種能力。首先,如果分?jǐn)?shù)也是0,那么整數(shù)就是0.由于符號是分開存儲(chǔ)的,我們同時(shí)具有-0和+0(詳見[3])。
其次,0的指數(shù)也用于表示非常小的數(shù)字(接近零)。然后該分?jǐn)?shù)必須是非零的,如果是正數(shù),則通過計(jì)算該數(shù)字
%0._f_ × 2?1022
這種表示是_非規(guī)范化_。先前討論的表示被稱為_標(biāo)準(zhǔn)化_。可以以規(guī)范化方式表示的最小的正數(shù)(非零)數(shù)是
%1.0 × 2?1022
最大的非正規(guī)化數(shù)字是
%0.1 × 2?1022
因此,在標(biāo)準(zhǔn)化和非標(biāo)準(zhǔn)化數(shù)字之間切換時(shí)沒有漏洞。
總結(jié):指數(shù)| (?1)_s_ × %1._f_ × 2_e_?1023 | normalized, 0 < e < 2047 |
| (?1)_s_ × %0._f_ × 2_e_?1022 | denormalized, e = 0, f > 0 |
| (?1)_s_ × 0 | e = 0, f = 0 |
| NaN | e = 2047, f > 0 |
| (?1)_s_ × ∞ (infinity) | e = 2047, f = 0 |
用_p_ = e - 1023,指數(shù)的范圍是
?1023 < p < 1024小數(shù)部分
并非所有小數(shù)都可以用JavaScript精確表示,如下所示:
> 0.1 + 0.2 0.30000000000000004
小數(shù)部分0.1和0.2都不能精確地表示為二進(jìn)制浮點(diǎn)數(shù)。但是,與實(shí)際值的偏差通常太小而不能顯示。加法導(dǎo)致偏差變得可見。另一個(gè)例子:
> 0.1 + 1 - 1 0.10000000000000009
表示0.1對于表示分?jǐn)?shù)110來說是個(gè)挑戰(zhàn)。困難的部分是分母10,其分母的因子分解是2×5.指數(shù)只允許你用2的冪除整數(shù),所以沒有辦法得到5英寸。比較:13不能精確地表示為小數(shù)部分。它近似于0.333333 ...
相反,將二進(jìn)制小數(shù)表示為小數(shù)部分總是可能的,您只需要收集足夠多的二進(jìn)制數(shù)(其中每十個(gè)都有一個(gè))。例如:
%0.001 = 18 = 12 × 2 × 2 = 5 × 5 × 5(2×5) × (2×5) × (2×5) = 12510 × 10 × 10 = 0.125比較小數(shù)部分
因此,當(dāng)您使用具有小數(shù)值的小數(shù)輸入時(shí),不應(yīng)直接比較它們。相反,考慮舍入誤差的上限。這樣的上限稱為machine epsilon。雙精度的標(biāo)準(zhǔn)epsilon值是2-53。
var epsEqu = function () { // IIFE, keeps EPSILON private var EPSILON = Math.pow(2, -53); return function epsEqu(x, y) { return Math.abs(x - y) < EPSILON; }; }();
上述功能可確保在正常比較不充分的情況下獲得正確結(jié)果:
> 0.1 + 0.2 === 0.3 false > epsEqu(0.1+0.2, 0.3) true最大整數(shù)
如果有人說“_x_是最大整數(shù)”,這意味著什么?這意味著可以表示范圍為0≤_n_≤_x_的每個(gè)整數(shù)_n_,并且對于大于_x_的任何整數(shù)都不能成立。 253符合該法案。以前的所有數(shù)字都可以表示:
> Math.pow(2, 53) 9007199254740992 > Math.pow(2, 53) - 1 9007199254740991 > Math.pow(2, 53) - 2 9007199254740990
但是下一個(gè)整數(shù)不能被表示:
> Math.pow(2, 53) + 1 9007199254740992
253的一些方面是上限可能是令人驚訝的。我們將通過一系列問題來看待他們。要記住的一件事是整數(shù)范圍的高端限制資源是分?jǐn)?shù);指數(shù)仍有增長空間。
為什么是53位?您有53位可用于幅度(不包括符號),但分?jǐn)?shù)只包含52位。這怎么可能?正如您在上面看到的那樣,指數(shù)提供了第53位:它移動(dòng)了分?jǐn)?shù),因此除零之外的所有53位數(shù)都可以表示,并且它有一個(gè)特殊值來表示零(連同零的一部分)。
為什么最高的整數(shù)不是253-1?通常,_x_位表示最低的數(shù)字是0,最高的數(shù)字是2_x_-1。例如,最高的8位數(shù)字是255.在JavaScript中,最高分?jǐn)?shù)確實(shí)用于數(shù)字253-1,但可以表示253,這要?dú)w功于指數(shù)的幫助 - 它僅僅是一個(gè)分?jǐn)?shù)_f_ = 0并且指數(shù)_p_ = 53(轉(zhuǎn)換后):
%1._f_ × 2_p_ = %1.0 × 253 = 253
為什么高于253的數(shù)字可以代表?
示例:
> Math.pow(2, 53) 9007199254740992 > Math.pow(2, 53) + 1 // not OK 9007199254740992 > Math.pow(2, 53) + 2 // OK 9007199254740994 > Math.pow(2, 53) * 2 // OK 18014398509481984
253×2的作品,因?yàn)橹笖?shù)可以使用。每乘以2只是將指數(shù)遞增1并且不影響分?jǐn)?shù)。因此,就最大分?jǐn)?shù)而言,乘以2的冪不是問題。為了明白為什么可以加2到253,而不是1,我們用前面的表擴(kuò)展53和54的附加位,以及_p_ = 53和_p_ = 54的行:
| | 54 | 53 | 52 | 51 | 50 | ... | 2 | 1 | 0 | (bits) |
| p=54 | 1 | f51 | f50 | f49 | f48 | ... | f0 | 0 | 0 | |
| p=53 | | 1 | f51 | f50 | f49 | ... | f1 | f0 | 0 | |
| p=52 | | | 1 | f51 | f50 | ... | f2 | f1 | f0 | |
查看行(_p_ = 53),應(yīng)該很明顯,JavaScript數(shù)字可以將位53設(shè)置為1.但是,因?yàn)榉謹(jǐn)?shù)_f_只有52位,所以位0必須為零。因此,只有偶數(shù)_x_可以在253≤_x_ <254范圍內(nèi)表示。在行(_p_ = 54)中,該間距增加到4的倍數(shù),范圍在254≤_x_ <255:
> Math.pow(2, 54) 18014398509481984 > Math.pow(2, 54) + 1 18014398509481984 > Math.pow(2, 54) + 2 18014398509481984 > Math.pow(2, 54) + 3 18014398509481988 > Math.pow(2, 54) + 4 18014398509481988
等等...
IEEE 754例外IEEE 754標(biāo)準(zhǔn)描述了五個(gè)例外,其中一個(gè)不能計(jì)算精確的值:
無效:執(zhí)行了無效操作。例如,計(jì)算負(fù)數(shù)的平方根。返回NaN [2]。
> Math.sqrt(-1) NaN
除以零:返回正負(fù)無窮[2]。
> 3 / 0 Infinity > -5 / 0 -Infinity
溢出:結(jié)果太大而無法表示。這意味著指數(shù)太高(_p_≥1024)。根據(jù)符號,有正面和負(fù)面溢出。返回正負(fù)無窮。
> Math.pow(2, 2048) Infinity > -Math.pow(2, 2048) -Infinity
下溢:結(jié)果太接近零來表示。這意味著指數(shù)太低(_p_≤-1023)。返回非規(guī)格化的值或零。
> Math.pow(2, -2048) 0
不精確:操作產(chǎn)生了不準(zhǔn)確的結(jié)果 - 要保留的分?jǐn)?shù)有太多有效數(shù)字。返回一個(gè)舍入結(jié)果。
> 0.1 + 0.2 0.30000000000000004 > 9007199254740992 + 1 9007199254740992
#3和#4是關(guān)于指數(shù),#5是關(guān)于分?jǐn)?shù)。 #3和#5之間的區(qū)別非常微妙:在第五個(gè)例子中,我們超過了分?jǐn)?shù)的上限(這將是整數(shù)計(jì)算中的溢出)。但只有超過指數(shù)的上限才稱為IEEE 754中的溢出。
結(jié)論在這篇博文中,我們研究了JavaScript如何將其浮點(diǎn)數(shù)轉(zhuǎn)換為64位。它根據(jù)IEEE 754標(biāo)準(zhǔn)中的雙精度進(jìn)行。由于數(shù)字的顯示方式,人們往往會(huì)忘記JavaScript不能精確地表示分母的因子分解包含2以外的數(shù)字的小數(shù)部分。例如,可以表示0.5(12),而0.6(35)不能表示。人們也往往忘記了三個(gè)組件符號,指數(shù),一個(gè)數(shù)字的小數(shù)部分一起工作來表示一個(gè)整數(shù)。但是,當(dāng)Math.pow(2,53)+ 2可以表示時(shí),會(huì)遇到這種情況,但Math.pow(2,53)+ 1不能。
網(wǎng)頁“IEEE-754 Analysis”允許您輸入一個(gè)數(shù)字并查看其內(nèi)部表示。
來源和相關(guān)閱讀這篇文章的來源:
“IEEE Standard 754 Floating-Point” by Steve Hollasch.
“Data Types and Scaling (Fixed-Point Blockset)” in the MATLAB documentation.
“IEEE 754-2008” on Wikipedia.
This post is part of a series on JavaScript numbers, which includes:
Displaying numbers in JavaScript
NaN and Infinity in JavaScript
JavaScript’s two zeros
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/95003.html
摘要:在符號位中,表示正,表示負(fù)。我們知道對于整型來說,內(nèi)存中存放的是該數(shù)的補(bǔ)碼。在計(jì)算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來表示和存儲(chǔ)。表示有效數(shù)字,。規(guī)定對于位的浮點(diǎn)數(shù),最高的位是 ...
摘要:在拿到這塊內(nèi)存后,是擁有完全操作的權(quán)利的。后面定義了一個(gè)函數(shù),并導(dǎo)出為函數(shù)。首先,使用在棧內(nèi)壓入一個(gè)位整型常數(shù),然后使用在棧內(nèi)壓入一個(gè)位整型常數(shù),之后調(diào)用指令,這個(gè)指 前端開發(fā)人員想必對現(xiàn)代瀏覽器都已經(jīng)非常熟悉了吧?HTML5,CSS4,JavaScript ES6,這些已經(jīng)在現(xiàn)代瀏覽器中慢慢普及的技術(shù)為前端開發(fā)帶來了極大的便利。得益于 JIT(Just-in-time)技術(shù),Java...
摘要:最近開始用來寫項(xiàng)目,寫起來還是挺順暢的。和在類型上的區(qū)別被稱作是一種動(dòng)態(tài)腳本語言,其中有一個(gè)被瘋狂詬病的特性缺乏靜態(tài)強(qiáng)類型。當(dāng)然,這是可以的,此時(shí)變量的類型已經(jīng)發(fā)生改變字符串?dāng)?shù)字。 最近開始用 TypeScript 來寫項(xiàng)目,寫起來還是挺順暢的。其實(shí)學(xué)習(xí) TypeScript,看它的官方文檔就夠了,剩下就是 coding 了。我這里主要是我在 TypeScript 學(xué)習(xí)過程中記錄的一些...
摘要:在和中都保留了數(shù)組的強(qiáng)引用,所以在中簡單的清除變量內(nèi)存并沒有得到釋放,因?yàn)檫€存在引用計(jì)數(shù)。而在中,它的鍵是弱引用,不計(jì)入引用計(jì)數(shù)中,所以當(dāng)被清除之后,數(shù)組會(huì)因?yàn)橐糜?jì)數(shù)為而被回收掉。其實(shí)我們主要注意的引用是不計(jì)引用計(jì)數(shù)的,就好理解了。 showImg(https://segmentfault.com/img/remote/1460000019147368?w=900&h=383); 前...
摘要:本文將會(huì)深入分析的引擎的內(nèi)部實(shí)現(xiàn)。該引擎使用在谷歌瀏覽器內(nèi)部。同其他現(xiàn)代引擎如或所做的一樣,通過實(shí)現(xiàn)即時(shí)編譯器在執(zhí)行時(shí)將代碼編譯成機(jī)器代碼。這可使正常執(zhí)行期間只發(fā)生相當(dāng)短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開始了一個(gè)系列博文旨在深入...
閱讀 1857·2021-09-22 15:45
閱讀 1639·2019-08-30 15:55
閱讀 1828·2019-08-29 11:16
閱讀 3301·2019-08-26 11:44
閱讀 702·2019-08-23 17:58
閱讀 2697·2019-08-23 12:25
閱讀 1624·2019-08-22 17:15
閱讀 3597·2019-08-22 16:09