国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript是怎樣編碼數(shù)字的[How numbers are encoded in Java

oysun / 2995人閱讀

摘要:譯者注規(guī)范化就是把小數(shù)點(diǎn)放在第一個非零數(shù)字的后面總結(jié)當(dāng)指數(shù)的范圍是十進(jìn)制分?jǐn)?shù)不是所有的十進(jìn)制分?jǐn)?shù)都能夠非常精確的表示例如和都不能夠被精確的表示成二進(jìn)制浮點(diǎn)數(shù)。相同的,也不能被精確表示成一個十進(jìn)制分?jǐn)?shù),它大概能被表示成。

在JavaScript中所有的數(shù)字都是浮點(diǎn)數(shù),本篇文章將介紹這些浮點(diǎn)數(shù)在JavaScript內(nèi)部是怎樣被轉(zhuǎn)為64位二進(jìn)制的。
我們會特別考慮整數(shù)的處理,所以讀完本篇之后,你會理解為什么會有以下結(jié)果發(fā)生:

> 9007199254740992 + 1
9007199254740992
> 9007199254740992 + 2
9007199254740994
1. JavaScript的數(shù)字

JavaScript數(shù)字全部是浮點(diǎn)數(shù)。 根據(jù)?IEEE 754標(biāo)準(zhǔn)中的64位二進(jìn)制(binary64), 也稱作雙精度規(guī)范(double precision)來儲存。從命名中可以看出,這些數(shù)字將以二進(jìn)制形式,使用64個字節(jié)來存儲。這些字節(jié)按照以下規(guī)則分配:

0 - 51 字節(jié)是 分?jǐn)?shù)f(fraction?)
52 - 62 字節(jié)是 指數(shù)(exponent?)
63 字節(jié) 是 標(biāo)志位 (sign)
標(biāo)志位 (s, sign) 指數(shù)(e, exponent?) 分?jǐn)?shù)(f, fraction?)
(1 bit) (11 bit) (52 bit)
63 62 51
52 0

他們按照以下規(guī)則表示一個數(shù)字: 如果標(biāo)志位是0, 表示這個數(shù)字為正數(shù),否則為負(fù)數(shù)。粗略來說,分?jǐn)?shù)f用來表示數(shù)字的‘?dāng)?shù)碼’(0-9),指數(shù)表示這個數(shù)字的‘點(diǎn)’在哪里。接下來我們會使用二進(jìn)制(雖然這并不是通常的浮點(diǎn)數(shù)表示方式)。并用一個%作為前綴來標(biāo)識。雖然JavaScript數(shù)字是以二進(jìn)制保存的,但輸出(打印)時(shí)通常是以10進(jìn)制顯示. 接下來的例子,我們也會沿用這一規(guī)則。

2. 分?jǐn)?shù)f

下表是一種表示非負(fù)浮點(diǎn)數(shù)的方法:
尾數(shù) (小數(shù)點(diǎn)后面的數(shù),significand?或 mantissa ) 以自然數(shù)字的形式保存‘?dāng)?shù)碼’,指數(shù)決定需要往左(負(fù)指數(shù))或者右(正指數(shù))移多少位。再忽略位數(shù),這個JavaScript數(shù)字就是 有理數(shù)1.f乘以2p。
譯者注: 這里指數(shù)用p而不是e來表示是因?yàn)閑是一個偏移量,第三點(diǎn)會詳細(xì)說明

比如以下例子:

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
2.1 表示一個整數(shù)

需要多少位來編碼一個整數(shù)呢? 尾數(shù)共有53個數(shù)碼,1個在‘點(diǎn)’的前面,52個在后面,如果p=52,我們就有一個53位的自然數(shù),現(xiàn)在的問題是最高位總是為1,也就是說我們不能隨便的使用所有的位。要去掉這個限制,我們需要2步,首先. 如果需要最高位是0,第二位是1的53位的數(shù)字,將p設(shè)置為51,這時(shí)分?jǐn)?shù)f最低位變成了‘點(diǎn)’后面的第一個數(shù)碼,也就是整數(shù)0。按照這個規(guī)律,直到指數(shù)p=0,分?jǐn)?shù)f=0,這就是數(shù)字1的編碼。

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位數(shù)字,我們還需要表示0,我們將在下一段詳細(xì)介紹。
需要注意的是,我們可以表示完整的53位整數(shù),因?yàn)闃?biāo)志位是另外儲存的。

3. 指數(shù)e

指數(shù)占11位,它可以表示0-2047(211-1), 為了支持負(fù)指數(shù),JavaScript使用偏移二進(jìn)制來編碼: 1023表示0,小于它的為負(fù),大于它的為正。這就意味著,減去1023才能得到正常點(diǎn)數(shù)字。因此我們之前使用的變量p就等于e-1023,也就是尾數(shù)乘以2e-1023
例如:

    %00000000000     0  →  ?1023  (最小的數(shù)字)
    %01111111111  1023  →      0
    %11111111111  2047  →   1024  (最大的數(shù)字)
                         
    %10000000000  1024  →      1
    %01111111110  1022  →     ?1 

如果需要一個負(fù)數(shù),只需要顛倒一下它的位數(shù),再減一

3.1 特殊的指數(shù)

有2個指數(shù)是保留位。最小的0,和最大的2047. 指數(shù)2047表示無窮大(infinity)和 NaN(非數(shù)字)值。IEEE 754標(biāo)準(zhǔn)有很多非數(shù)字值, 但是JavaScript把他們都表示為NaN。指數(shù)為0時(shí)有兩個意思。1. 如果分?jǐn)?shù)f也是0,表示這個數(shù)字就是0.因?yàn)闃?biāo)志位是多帶帶存儲的。所以我們有+0和-0;

然后指數(shù)0也可以用來表示非常小的數(shù)字(接近0)。此時(shí)分?jǐn)?shù)f必須為非0,而且,如果這個數(shù)字是由%0.f?× 2?1022算出來的,這個表示方式叫做非規(guī)范化,而之前我們討論的表示方式叫規(guī)范化。最小的非0正數(shù)可以被規(guī)范化為: %1.0 × 2?1022。 最大的非規(guī)范化數(shù)字為: %0.1 × 2?1022, 所以,從規(guī)范化到非規(guī)范化是過渡是平滑的。
譯者注: 規(guī)范化就是把小數(shù)點(diǎn)放在第一個非零數(shù)字的后面

3.2 總結(jié):
(?1)s?× %1.f?× 2e?1023 normalized, 0
(?1)s?× %0.f?× 2e?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

當(dāng)p?=?e?? 1023, 指數(shù)的范圍是?1023 4. 十進(jìn)制分?jǐn)?shù)

不是所有的十進(jìn)制分?jǐn)?shù)都能夠非常精確的表示, 例如:

> 0.1 + 0.2
0.30000000000000004

0.1和0.2都不能夠被精確的表示成二進(jìn)制浮點(diǎn)數(shù)。但是這個偏差通常非常非常小,小到不能夠被表示出來,加法可以使這個偏差變得可見:

> 0.1 + 1 - 1
0.10000000000000009

表示0.1相當(dāng)于表示一個分?jǐn)?shù)110,難的部分在于分母是10,10素?cái)?shù)分解是2*5. 而指數(shù)只能分解2,所以沒有辦法得到5。相同的, 1/3也不能被精確表示成一個十進(jìn)制分?jǐn)?shù),它大概能被表示成0.333333。
但相對的。要用十進(jìn)制表示一個2進(jìn)制分?jǐn)?shù)卻是永遠(yuǎn)可行的,值需要使用足夠的2(每個10都有1個2)。

%0.001 =?1/8?=?1/2 × 2 × 2?=?5 × 5 × 5/(2×5) × (2×5) × (2×5)?=?125/10 × 10 × 10?= 0.125
4.1 對比十進(jìn)制分?jǐn)?shù)

因此,當(dāng)你要處理10進(jìn)制分?jǐn)?shù),不要直接去比較他們,先想一想,它可能會有一個上限,比如有一個上限叫做機(jī)器最小數(shù)?machine epsilon. 標(biāo)準(zhǔn)的雙精度數(shù)的最小數(shù)為?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
5. 最大的整數(shù)

“x 是最大的整數(shù)”這句話是什么意思呢?它的意思是說,任意整數(shù)n在?0 ≤?n?≤?x?范圍內(nèi)都是可以被表示的。也就是說如果大于x,將無法表示。比如253?。任何比它小的數(shù)字都可以被表示。

> Math.pow(2, 53)
9007199254740992
> Math.pow(2, 53) - 1
9007199254740991
> Math.pow(2, 53) - 2
9007199254740990
但比它大的就不行
> Math.pow(2, 53) + 1
9007199254740992

關(guān)于253?這個上限,有一些很令人驚奇的表現(xiàn)。我們將用一些問題來解釋這些現(xiàn)象。你要記住的是,這個上限是分?jǐn)?shù)f的上限,指數(shù)e部分其實(shí)還有空間。

為什么是53位呢?你有53位來表示數(shù)的大小,除去標(biāo)志位。但是分?jǐn)?shù)f卻是由52位組成的,這是為什么呢。從前面的文章可以看出,指數(shù)e從第53位開始,它會移動分?jǐn)?shù)f,所以這個53位的數(shù)字(除了0)可以被表示出來,并且有一個特別的數(shù)字去表示0(并且分?jǐn)?shù)f也是0).

為什么最大的數(shù)不是253?1??通常來說,x位就說明最小數(shù)是0,最大值是2x?1.?比如8位數(shù)字最大是255。而在JavaScript里,最大的分?jǐn)?shù)f確實(shí)是253?1,但253?也可以被表示出來,因?yàn)橛兄笖?shù)e的幫助。它只要讓分?jǐn)?shù)f等于0,指數(shù)e等于53即可。

%1.f?× 2p?= %1.0 × 253?= 253

為什么大于253就不能表示了呢?例如:

> 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ù)e還可以用,乘以2僅僅需要指數(shù)e加一,而不影響分?jǐn)?shù)f。所以乘以2的冪不是問題,只要分?jǐn)?shù)f沒有超過上限,那為什么2加253也可以表示正確,1卻不可以呢,我們擴(kuò)大一下之前的,加上53 和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位必須位0,而只有253?≤?x?< 254中的偶數(shù)數(shù)字x可以被表示。在p=54時(shí),這個空間增加到乘以4,在?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
6. IEEE 754 的例外

IEEE 754標(biāo)準(zhǔn)描述了5中例外?, 當(dāng)出現(xiàn)這些例外,就無法算出準(zhǔn)確的數(shù)字。

1. 無效 : 進(jìn)行一個無效操作。例如,給一個負(fù)數(shù)開平方,返回NaN

> Math.sqrt(-1)
NaN

2. 除以0 : 返回正或者負(fù)的infinity(無窮大)

> 3 / 0
Infinity
> -5 / 0
-Infinity

3. 溢出(overflow) : 結(jié)果太大,無法表示。這時(shí)是指數(shù)已經(jīng)太大,?(p?≥ 1024).根據(jù)標(biāo)志位,正或者負(fù)溢出,返回正或者負(fù)的infinity(無窮大)。

> Math.pow(2, 2048)
Infinity
> -Math.pow(2, 2048)
-Infinity

4. 潛流(underflow): 結(jié)果太接近于0,這時(shí)是指數(shù)已經(jīng)太小(p?≤ ?1023).?返回一個非規(guī)范化的數(shù)字,或者0.

> Math.pow(2, -2048)
0

5. 不精確(Inexact): 一個操作返回不精確的結(jié)果 - 有太多有意義的數(shù)字需要分?jǐn)?shù)f去存,那就返回一個四舍五入的結(jié)果

> 0.1 + 0.2
0.30000000000000004
    
> 9007199254740992 + 1
9007199254740992

上面的第三點(diǎn)和第四點(diǎn)是關(guān)于指數(shù)的,第五點(diǎn)是關(guān)于分?jǐn)?shù)f的,第三點(diǎn)和第五點(diǎn)的差別非常小,第五點(diǎn)的第二個例子,我們已經(jīng)接近了分?jǐn)?shù)f的最大值(這也可以算是一個溢出操作)。但根據(jù)?IEEE 754只有超過了指數(shù)的范圍才算溢出。

7. 結(jié)論

本篇文章中,我們觀察了JavaScript是怎樣把浮點(diǎn)數(shù)存進(jìn)64位中的。它之所以這么做是根據(jù)?IEEE 754 標(biāo)準(zhǔn)中的雙精度。因?yàn)槲覀兂3M洠琂avaScript對于分母質(zhì)因分解不僅包含2的數(shù)字 是無法精確表示的。比如0.5(1/2),是可以精確表示的,但0.6(3/5)就不能。我們很容易忘記一個整數(shù)是由標(biāo)志位,分?jǐn)?shù)f,指數(shù)3部分組成,然后就會面對Math.pow(2, 53) + 2?可以計(jì)算正確,而Math.pow(2, 53) + 1會計(jì)算錯誤的問題。

8. 資源和引用

? “IEEE Standard 754 Floating-Point” - Steve Hollasch.
? “Data Types and Scaling (Fixed-Point Blockset)” in the MATLAB documentation.
? “IEEE 754-2008” on Wikipedia

本文也同時(shí)是JavaScript 數(shù)字系列?, 它包含:

JavaScript中的數(shù)字顯示

JavaScript中的NaN 和 Infinity

JavaScript的兩種0

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108771.html

相關(guān)文章

  • js 中 number 為何很怪異

    摘要:但這個數(shù)值并不安全從到中間的數(shù)字并不連續(xù),而是離散的。對象中的常量表示與可表示的大于的最小的浮點(diǎn)數(shù)之間的差值。絕對值的最大安全值。尋找奇怪現(xiàn)象的原因?yàn)槭裁唇Y(jié)果是與的逼近算法類似。 js 中的 number 為何很怪異 聲明:需要讀者對二進(jìn)制有一定的了解 對于 JavaScript 開發(fā)者來說,或多或少都遇到過 js 在處理數(shù)字上的奇怪現(xiàn)象,比如: > 0.1 + 0.2 0.30000...

    MRZYD 評論0 收藏0
  • 圖解:JavaScript中Number一些表示上/下限

    摘要:例如指數(shù)實(shí)際值為,在單精度浮點(diǎn)數(shù)中的指數(shù)域編碼值為,即采用指數(shù)的實(shí)際值加上固定的偏移值的辦法表示浮點(diǎn)數(shù)的指數(shù),好處是可以用長度為個比特的無符號整數(shù)來表示所有的指數(shù)取值,這使得兩個浮點(diǎn)數(shù)的指數(shù)大小的比較更為容易。 自己整理、設(shè)計(jì)的,轉(zhuǎn)載請注明原帖。先從這個demo看起:http://alvarto.github.io/Visu... 數(shù)軸 showImg(http://segmentfa...

    SillyMonkey 評論0 收藏0

發(fā)表評論

0條評論

oysun

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<