av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

JS數(shù)值存儲運算原理

前言

相信大家都看過這些曾經(jīng)在社區(qū)比較火的文章:

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)武侯免費做網(wǎng)站提供優(yōu)質(zhì)的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千多家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。

  • 0.1 + 0.2 與0.3為什么不相等?
  • 為什么 3.0000000000000002 === 3表達式為true ?
  • 等...

造成這些問題的背后原因都是由于javaScript采用了 IEEE754 標準,全稱 IEEE 二進制浮點數(shù)算術(shù)標準。所以說這個問題其實不止是會在javaScript中出現(xiàn),而是「其他遵循 [IEEE 754]標準的語言也會出現(xiàn)這個問題」

并且自己在最近的工作中也遇到了這個問題,由于javaScript精度丟失而造成詭異問題!

javaScript車禍現(xiàn)場

上面三個例子在我們在控制臺里面驗證一遍,是不是瞬間覺得奇怪的知識又增加了?

javaScript這令人窒息的操作是不是讓很多后端人員口吐芬芳了,甚至是很多前端人員都覺得明明都是送分題,卻成了JS的送命題,工作中許多不經(jīng)意間寫出的bug,往往是由于JS的不按常理出牌。

說了這么多,我們也改變不了這一現(xiàn)狀,那就嘗試去理解它吧~

計算機運算

學過計算機相關(guān)同學都知道,我們的計算機底層元算采用的是二進制,而不是我們平常用的十進制!

二進制

「為什么計算機要采用二進制,而不是十進制?」

以下是在知乎上看到的回答,我覺得這個理解是比較到位的。

計算機本身的理論模型,和采用哪個數(shù)學上的進制完全無關(guān),十進制也好,五進制也好,二進制也好,進制在數(shù)學上都是等價的,并沒有哪個進制擁有其他進制無法實現(xiàn)的計算。

但計算機的實現(xiàn)是個工程問題,需要和真實的物理環(huán)境打交道,我們現(xiàn)在是用電路去實現(xiàn)我們的計算機模型,那就需要和物理電路打交道,需要考慮到信號的衰減延遲,電路器件的各種電氣特性,什么電磁波干擾電流擾動,也就是會有失真的情況出現(xiàn),而要最大程度避免衰減,失真對計算機這個完美世界造成破壞,同時要考慮電路的設(shè)計,制作成本,就需要最簡單化的物理實現(xiàn)方案。

電子計算機確實是可以做成十進制的,就像題主說的像燈泡亮度分成十種亮度那樣,但與此同時會出現(xiàn)很多的工程問題,比如對電子器件的精度和穩(wěn)定性要求很高,電路設(shè)計的復雜性提升等等,到頭來還不如就用二進制,在成本和質(zhì)量上最劃算。

事實上,不但十進制不行,十六進制、八進制、四進制也都比不上二進制。理論上已經(jīng)證明效率最高的進制是e,離e最近的其實是三進制。但三進制不方便表示,不過也有人研究,前蘇聯(lián)就做過三進制計算機,國內(nèi)也有,但并沒有走出實驗室。效率是一方面,實現(xiàn)成本又是一方面,最終大家還是覺得二進制實現(xiàn)起來最方便。

原碼、反碼、補碼

「為運算方便,機器數(shù)有 3 種表示法,即原碼、反碼和補碼」。

原碼

原碼是一種計算機中對數(shù)字的二進制定點表示法。「原碼表示法在數(shù)值前面增加了一位符號位」。

反碼

正數(shù)的反碼和原碼一樣,

負數(shù)的反碼就是在原碼的基礎(chǔ)上符號位保持不變,其他位取反。

補碼

正數(shù)和 0 的補碼就是該數(shù)字本身。

「負數(shù)的補碼則是將其對應正數(shù)按位取反再加 1」

二進制轉(zhuǎn)換

「正整數(shù)的轉(zhuǎn)換方法」:除二取余,然后倒序排列,高位補零。

例如21的轉(zhuǎn)換

商  余
21/2  10  1
10/2  5   0
5/2   2   1
2/2   1   0
1/2   0   1

21的二進制為10101,然后高位補0為00010101

「負整數(shù)的轉(zhuǎn)換方法」:將對應的正整數(shù)轉(zhuǎn)換成二進制后,對二進制取反,然后對結(jié)果再加一。

例如-21
先把21轉(zhuǎn)換成二進制 00010101
逐位取反:11101010
再加1:11101011(補碼)

「小數(shù)的轉(zhuǎn)換方法」:對小數(shù)點以后的數(shù)乘以2,取整數(shù)部分,再取小數(shù)部分乘2,以此類推……直到小數(shù)部分為0或位數(shù)足夠。取整部分按先后順序排列即可。

例如123.4:
0.4*2=0.8 ——————-> 取0
0.8*2=1.6 ——————-> 取1
0.6*2=1.2 ——————-> 取1
0.2*2=0.4 ——————-> 取0
0.4*2=0.8 ——————-> 取0
………… 后面就是循環(huán)了
按順序?qū)懗觯?.4 = 0.01100110……(0110循環(huán))
整數(shù)部分123的二進制是 1111011
則123.4的二進制表示為:1111011.011001100110……

發(fā)現(xiàn)了什么?十進制小數(shù)轉(zhuǎn)二進制后大概率出現(xiàn)無限位數(shù)!但我們的javaScript采用了「IEEE754」 標準,全稱 「IEEE 二進制浮點數(shù)算術(shù)標準」。

由于IEEE 754尾數(shù)位數(shù)限制,會將后面多余的位截掉。

javaScript 與 IEEE 754

“JavaScript 采用 IEEE 754 標準,數(shù)值存儲為64位雙精度格式,數(shù)值精度最多可以達到 53 個二進制位(1 個隱藏位與 52 個有效位)

在這個標準下,我們會用1位存儲 S(sign),0 表示正數(shù),1 表示負數(shù)。用11位存儲 E(exponent) + bias,對于11位來說,bias 的值是 2^(11-1) - 1,也就是 1023。用52 位存儲 Fraction。

由于javaScript采用的是IEE754標準,所以在進制之間的轉(zhuǎn)換過程中可能會導致精度丟失,這是造成javaScript運算翻車的罪魁禍首!

破案

0.1+0.2 與 0.3為什么不相等?

0.1.toString(2)
// '0.0001100110011001100110011001100110011001100110011001101'   // 57
// 按 IEEE754 格式  57 - 4 = 52可以精確存儲
0.2.toString(2)
// '0.001100110011001100110011001100110011001100110011001101' // 56
// 按 IEEE754 格式  56 - 3 = 53  會丟棄最后一位數(shù)
0.3.toString(2)
// '0.010011001100110011001100110011001100110011001100110011'  // 56
// 按 IEEE754 格式  56 - 2 = 54  會丟棄最后兩位數(shù)

/*總結(jié):
存儲0.1沒有誤差, 存儲 0.2丟棄最后一位 1  存儲0.3丟棄最后2位 11,
顯然存儲0.3丟棄的數(shù)值>存儲0.2丟棄的數(shù)值
經(jīng)分析 0.1 + 0.2   應該大于 0.3
*/
0.1 + 0.2 > 0.3  // true

為什么 3.0000000000000002 === 3表達式為true ?

手動將 3.0000_0000_0000_0002轉(zhuǎn)換成二進制浮點數(shù)

整數(shù)部分為 11?

小數(shù)部分0.0000_0000_0000_0002

0.0000_0000_0000_0002.toString(2)

'0.0000000000000000000000000000000000000000000000000000111001101001010110010100101111101100010001001101111'

注意小數(shù)點后面正好有52個0

0.0000_0000_0000_0002.toString(2).length  // 105 105

將 3.0000000000000002 用 IEEE754 格式表示

  1. 符號S: 正數(shù),0
  2. 指數(shù)位E:11 = 1.1 * 2^1 (二進制),E = 1023 + 1 = 1024 = 10000000000(二進制)
  3. 尾數(shù)位M:0.1.....0

所以該浮點數(shù)格式為: 0   1000_0000_000   1...000(一共52個0) 這個數(shù)正好是3。

如何解決精度問題?

目前有許多第三方庫可以解決javaScript精度丟失的問題

math.js

math.js是JavaScript和Node.js的一個廣泛的數(shù)學庫。支持數(shù)字,大數(shù),復數(shù),分數(shù),單位和矩陣等數(shù)據(jù)類型的運算。

官網(wǎng):mathjs.org/ GitHub:github.com/josdejong/m…

0.1+0.2 ===0.3實現(xiàn)代碼:

var math = require('mathjs')
console.log(math.add(0.1,0.2))//0.30000000000000004
console.log(math.format((math.add(math.bignumber(0.1),math.bignumber(0.2)))))//'0.3'

decimal.js

為 JavaScript 提供十進制類型的任意精度數(shù)值。

官網(wǎng):mikemcl.github.io/decimal.js/

GitHub:github.com/MikeMcl/dec…

var Decimal = require('decimal.js')
x = new  Decimal(0.1)
y = 0.2
console.log(x.plus(y).toString())//'0.3'

bignumber.js

用于任意精度算術(shù)的JavaScript庫。

官網(wǎng):mikemcl.github.io/bignumber.j…

Github:github.com/MikeMcl/big…

var BigNumber = require("bignumber.js")
x = new BigNumber(0.1)
y = 0.2
console.log(x.plus(y).toString()) //'0.3'

本文標題:JS數(shù)值存儲運算原理
鏈接URL:http://uogjgqi.cn/article/djsohse.html
掃二維碼與項目經(jīng)理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流