成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

由parseInt 引發(fā)的問題---想到浮點(diǎn)運(yùn)算精度丟失---看透js number 的 encod

hightopo / 2863人閱讀

摘要:如題先陳述下問題背景偶爾測(cè)測(cè)自己寫的計(jì)算器,隨便輸入玩嘛,然后發(fā)生下面詭異的事情當(dāng)我從一個(gè)輸入到十個(gè)的時(shí)候,過程顯示都是正確的,像這樣繼續(xù)輸入一個(gè)的時(shí)候,然后就這個(gè)樣子了什么原因呢看了下自己的代碼,代碼重要部分長(zhǎng)這樣的這里用了一下強(qiáng)制轉(zhuǎn)化為

如題 先陳述下問題背景

偶爾測(cè)測(cè)自己寫的計(jì)算器,隨便輸入玩嘛,然后發(fā)生下面詭異的事情:
當(dāng)我從一個(gè) 1 輸入到十個(gè) 1 的時(shí)候,過程顯示都是正確的,像這樣:

繼續(xù)輸入一個(gè) 1 的時(shí)候,然后就這個(gè)樣子了:

什么原因呢?
看了下自己的代碼,代碼重要部分長(zhǎng)這樣的:

這里用了一下 parseInt 強(qiáng)制轉(zhuǎn)化為整數(shù)類型 (研究了之后,才懊悔,這個(gè)方法缺陷太多,研究的不深入就容易寫垃圾麻煩代碼--)

摸索問題怎么產(chǎn)生的

出現(xiàn)問題,只能一點(diǎn)一點(diǎn)扒,拆分成小塊找問題。這個(gè)過程,如果有耐心的話,還是可以學(xué)到很多,提升很多,是一件很愉快的事情,工作并不是做的越多越好,而是帶著思想做的越深越好。
廢話結(jié)束

首先嘗試一下 console parseInt
嘗試剛剛數(shù)字, 從十個(gè) 1 上開始加

著實(shí)搞不懂這是怎么回事唉

parseInt 深入理解 (字符串,小數(shù),整數(shù)之間的轉(zhuǎn)換)

除了我試出來(lái)的這個(gè)問題,網(wǎng)上還看到這樣的奇葩 ParseInt(0.0000008, 10)

所以了解一下 parseInt 究竟在轉(zhuǎn)換過程中做了啥是非常有必要的

parseInt 在將字符串或者小數(shù)(我們眼中的而已,其實(shí)他都一視同仁)轉(zhuǎn)換為整數(shù)時(shí),做了那幾步呢?

取出參數(shù)

將傳入的第一個(gè)參數(shù)轉(zhuǎn)為字符串 調(diào)用了String()方法

根據(jù)第二個(gè)參數(shù),再對(duì)字符串進(jìn)行int轉(zhuǎn)換

String()方法會(huì)讓原來(lái)的參數(shù)改變,比如無(wú)數(shù)個(gè)1

再比如鏈接中提到的 0.0000008

可見String()將其科學(xué)計(jì)數(shù)法再轉(zhuǎn)為字符串,造成只取到了 8

通俗理解一下,第一個(gè)參數(shù)是字符串還好,如果不是字符串就造成麻煩了,非字符串的數(shù)值在調(diào)用 String 進(jìn)行轉(zhuǎn)換時(shí)會(huì)出問題的,這就是 parseInt 弊端

(感興趣的 可以再深入 String 這個(gè)方法做了哪些事情吧。這里根據(jù)es5標(biāo)準(zhǔn)寫了一篇String 內(nèi)部處理邏輯標(biāo)準(zhǔn))

繼續(xù)嘗試 parseInt ,百試不厭,就會(huì)發(fā)現(xiàn),當(dāng)增加到一定大的數(shù)時(shí)候,會(huì)發(fā)現(xiàn)不變了,臨界值如下:

不僅僅嘗試了 parseInt 同時(shí)嘗試了 + 單元運(yùn)算符,結(jié)果一樣, 這應(yīng)該跟 paseInt 沒多大關(guān)系了吧,應(yīng)該是因?yàn)榫幋a存儲(chǔ)之類的問題吧

所以啊,即使沒有最大值問題, parseInt 還是少用,可以Math.round等就不會(huì)出現(xiàn)這個(gè)問題,為啥呢,可以深入一波

是怎么聯(lián)系上 encoded 問題的呢?

上面例子測(cè)試,發(fā)現(xiàn),當(dāng) parseInt 的第一個(gè)參數(shù)傳入的是數(shù)字并且越來(lái)越大時(shí),值就停留在 9007199254740992。當(dāng)然排除特殊的科學(xué)計(jì)數(shù)法(這會(huì)導(dǎo)致 js 在表示 number 時(shí)隱藏部分?jǐn)?shù)字)后變換只得到1或者8或者其他等等情況,為什么停留在這個(gè)數(shù)字呢?

查看 ES5 標(biāo)準(zhǔn), 發(fā)現(xiàn) JS 對(duì) number encoded 的處理很獨(dú)特,總結(jié)如下:

Number類型統(tǒng)一按浮點(diǎn)數(shù)處理,64位存儲(chǔ),整數(shù)是按最大53位來(lái)算最大最小數(shù)的

Number value
primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value.

查閱 IEEE 754

圖片顯示雙精度 64 位浮點(diǎn)數(shù)的存儲(chǔ)格式為:

s * m * 2^e

s 是符號(hào)位,表示正負(fù),由 1 bit

m 是小數(shù)位,由 52 bits

e 是指數(shù)位, 由 11 bits

64位表示雙精度浮點(diǎn)數(shù),可以表示 2^64 - 2^53 + 3 種數(shù)值

這些數(shù)中包括 number 所包括的各種類型(NaN , infinity, 浮點(diǎn)數(shù)),這些數(shù)值是怎么在 64bits 中存儲(chǔ)的呢?可以看這一篇JS雙精度64位 Number

其中正常的浮點(diǎn)數(shù)又包含了不丟失精度的可能會(huì)丟失精度的,不丟失精度的數(shù)通俗理解就是加 1 不會(huì)算錯(cuò),所以 Number.MAX_SAFE_INTEGER 的值為 9007199254740991 因?yàn)?9007199254740991 + 1 不會(huì)算錯(cuò),如果用 9007199254740992 +1 就會(huì)算錯(cuò)了,如下圖

所以稱之為 max_safe_interger

其實(shí) number 能表示的最大整數(shù)是 2^53,為什么呢?

為什么是 2^53 而不是 2^52?

根據(jù) IEEE754 制定的標(biāo)準(zhǔn),應(yīng)該只有 52 bits 用來(lái)表示小數(shù)位的,最大也應(yīng)該是 2^51 - 1 呀!

先普及 52 bits 表示的二進(jìn)制轉(zhuǎn)換為十進(jìn)制為什么最大是 2^51 - 1,有助于小白理解 2^53 而不至于混淆。

52 bits

當(dāng) 52 位上都是 1 的時(shí)候,轉(zhuǎn)換為十進(jìn)制得到的數(shù)最大
根據(jù)二進(jìn)制轉(zhuǎn)十進(jìn)制的方法,將 52 個(gè) 1……1 轉(zhuǎn)換為十進(jìn)制,方程為:
2^0 + 2^1 + 2^2 + …… + 2^51
觀察得知這是一個(gè)
首位為 2
公比為 2
等比數(shù)列求合 a1 * (1 -q^n)/1-q (q != 1)
           na1 (q == 1)

所以 52 bits 能表示的最大十進(jìn)制數(shù)為 2^51 - 1,同理 53 bits 能表示的最大十進(jìn)制數(shù)為 2^52 - 1

等比數(shù)列求合公式推導(dǎo)鏈接

現(xiàn)在思考為什么是 2^53 呢?

Why 53 bits? You have 53 bits available for the magnitude (excluding the sign), but the fraction comprises only 52 bits. How is that possible? As you have seen above, the exponent provides the 53rd bit: It shifts the fraction, so that all 53 bit numbers except the zero can be represented and it has a special value to represent the zero (in conjunction with a fraction of 0).

這段話的意思就是,在表示最大數(shù)的時(shí)候,存儲(chǔ)指數(shù)位的 11 bits 分給小數(shù)位 1 bit,就變成了 53 bits,就算這樣也應(yīng)該最大是 2^53 - 1 啊,為什么不是 2^53 - 1呢?

為什么是 2^53 而不是 2^53 - 1呢?
Why is the highest integer not 2^53?1? Normally, x bit mean that the lowest number is 0 and the highest number is 2x?1. For example, the highest 8 bit number is 255. In JavaScript, the highest fraction is indeed used for the number 2^53?1, but 2^53 can be represented, thanks to the help of the exponent – it is simply a fraction f = 0 and an exponent p = 53

這段話意思是說(shuō),最高的小數(shù)位對(duì)于 2^53 - 1是有必要的而且已經(jīng)有的,但是 2^53 也是可以轉(zhuǎn)化過來(lái)的。什么意思呢,對(duì)于二進(jìn)制來(lái)說(shuō),小數(shù)點(diǎn)前保留一位,規(guī)格化后始終是 1.*,節(jié)省了 1 bit,這個(gè) 1 并不需要保存。

發(fā)現(xiàn)超過 2^53 的十進(jìn)制數(shù)也是可以表示的,那么是怎么存儲(chǔ)的的,還是指數(shù)位提供了幫助,這也就是為什么可以在 2^53 上以 2 的倍數(shù)變化,可以加 2,加 4 ……,但是加 1 不行,不能精確顯示。同樣比 2^53 大且比 2^54 小的數(shù)在瀏覽器中顯示,是其 2 的倍數(shù)才能正確顯示,否則不能

,x can be represented in the range 2^53 ≤ x < 2^54. In row (p=54), that spacing increases to multiples of four, in the range 2^54 ≤ x < 2^55 …… and so on

所以 max_safe_interger 是 2^53 - 1

之前常見到 js unicode utf-16 引起的一些問題,這次遇見的是 js encoded 問題
js string 存儲(chǔ)是 utf-16 encoding form
js number 存儲(chǔ)是 IEEE 754 雙精度浮點(diǎn)數(shù) 64 bits 標(biāo)準(zhǔn)

JS 浮點(diǎn)運(yùn)算丟失精度問題

在計(jì)算 0.1 + 0.1 出錯(cuò)的問題上,精度是怎么丟失的呢,這個(gè)問題和 parseInt 思考方式基本類似,看這個(gè)過程中有哪些步驟,在哪步會(huì)丟失精度

首先這是一個(gè)表達(dá)式,要先將表達(dá)式的 左右對(duì)象 裝進(jìn)計(jì)算機(jī)

轉(zhuǎn)換為二進(jìn)制

用二進(jìn)制科學(xué)計(jì)數(shù)法表示

表示成 IEEE 754 形式

第一步和第三步都有可能丟失精度

回到最開始的問題,怎么解決呢?

替換 parseInt 為 Math.round

若想用 大于 2^53 的數(shù)進(jìn)行計(jì)算的話,思考下導(dǎo)入什么 bitInterger 的庫(kù)用一用吧

多看幾個(gè)例子:


以上屬于精度丟失問題,間隔計(jì)算

科學(xué)計(jì)數(shù)法存儲(chǔ)展示問題

參考
http://2ality.com/2012/04/num...
https://en.wikipedia.org/wiki...
http://es5.github.io/#x8
http://blog.csdn.net/JustJava...

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92951.html

相關(guān)文章

  • [ JS 基礎(chǔ) ] JS 浮點(diǎn)數(shù)四則運(yùn)算精度丟失問題 (3)

    摘要:基于這個(gè)問題運(yùn)動(dòng)基礎(chǔ)問題,我想應(yīng)該也有一部分人沒有認(rèn)真對(duì)待過中浮點(diǎn)數(shù)的四則運(yùn)算出現(xiàn)的問題。解決方案引自解決方案為了解決浮點(diǎn)數(shù)運(yùn)算不準(zhǔn)確的問題,在運(yùn)算前我們把參加運(yùn)算的數(shù)先升級(jí)的的次方到整數(shù),等運(yùn)算完后再降級(jí)的的次方。 基于這個(gè)問題:javascript運(yùn)動(dòng)基礎(chǔ)問題 ,我想應(yīng)該也有一部分人沒有認(rèn)真對(duì)待過js中浮點(diǎn)數(shù)的四則運(yùn)算出現(xiàn)的問題。 1.問題描述 示例代碼: var x ...

    hoohack 評(píng)論0 收藏0
  • JS最新基本數(shù)據(jù)類型:BigInt

    摘要:意外四舍五入會(huì)損害程序的可靠性和安全性。下面是一些例子構(gòu)造函數(shù)與其他基本類型一樣,可以使用構(gòu)造函數(shù)創(chuàng)建??偨Y(jié)是一種新的數(shù)據(jù)類型,用于當(dāng)整數(shù)值大于數(shù)據(jù)類型支持的范圍時(shí)。 為了保證的可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! BigInt數(shù)據(jù)類型的目的是比Number數(shù)據(jù)類型支持的范圍更大的整數(shù)值。在對(duì)大整數(shù)執(zhí)行數(shù)學(xué)運(yùn)算時(shí),以任意精...

    lwx12525 評(píng)論0 收藏0
  • JavaScript填坑史

    摘要:和深入理解在和深入理解這篇博客里筆者曾做過總結(jié),我們知道試單線程的產(chǎn)物,兩個(gè)函數(shù)就是利用了插入代碼的方式實(shí)現(xiàn)了偽異步,和的原理實(shí)際上是一樣的。綜上所述,其實(shí)終歸是單線程產(chǎn)物。無(wú)論如何異步都不可能突破單線程這個(gè)障礙。 說(shuō)明:??這是筆者平時(shí)積累的一些覺得比較有意思或是比較有難度的JavaScript題目理解和心得,會(huì)保持長(zhǎng)期更新。 1.setTimeout和setInterval深入理解...

    objc94 評(píng)論0 收藏0
  • JavaScript 基礎(chǔ)知識(shí) - 入門篇(一)

    摘要:如圖意義位用來(lái)表示符號(hào)位位用來(lái)表示指數(shù)位表示尾數(shù)浮點(diǎn)數(shù),比如無(wú)限循環(huán)無(wú)限循環(huán)此時(shí)只能模仿十進(jìn)制進(jìn)行四舍五入了,但是二進(jìn)制只有和兩個(gè),于是變?yōu)樯崛搿_@即是計(jì)算機(jī)中部分浮點(diǎn)數(shù)運(yùn)算時(shí)出現(xiàn)誤差,丟失精度的根本原因。 showImg(http://ww1.sinaimg.cn/large/9c47d583gy1fmtw1ma9g4j21hc0u0ach.jpg); 前言 最近一直有小伙伴跟我說(shuō)J...

    sarva 評(píng)論0 收藏0
  • JS中如何理解浮點(diǎn)數(shù)?

    摘要:本文通過介紹的二進(jìn)制存儲(chǔ)標(biāo)準(zhǔn)來(lái)理解浮點(diǎn)數(shù)運(yùn)算精度問題,和理解對(duì)象的等屬性值是如何取值的,最后介紹了一些常用的浮點(diǎn)數(shù)精度運(yùn)算解決方案。浮點(diǎn)數(shù)精度運(yùn)算解決方案關(guān)于浮點(diǎn)數(shù)運(yùn)算精度丟失的問題,不同場(chǎng)景可以有不同的解決方案。 本文由云+社區(qū)發(fā)表 相信大家在平常的 JavaScript 開發(fā)中,都有遇到過浮點(diǎn)數(shù)運(yùn)算精度誤差的問題,比如 console.log(0.1+0.2===0.3)// fa...

    bang590 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

hightopo

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<