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

資訊專欄INFORMATION COLUMN

JavaScript 精度丟失問(wèn)題

iOS122 / 1557人閱讀

摘要:排除直接使用的數(shù)太大或太小超出范圍,出現(xiàn)這種問(wèn)題的情況基本是浮點(diǎn)數(shù)的小數(shù)部分在轉(zhuǎn)成二進(jìn)制時(shí)丟失了精度,所以我們可以將小數(shù)部分也轉(zhuǎn)換成整數(shù)后再計(jì)算。

// 1. 兩數(shù)相加
// 0.1 + 0.2 = 0.30000000000000004
// 0.7 + 0.1 = 0.7999999999999999
// 0.2 + 0.4 = 0.6000000000000001
// 2.22 + 0.1 = 2.3200000000000003

// 2. 兩數(shù)相減
// 1.5 - 1.2 = 0.30000000000000004
// 0.3 - 0.2 = 0.09999999999999998

// 3. 兩數(shù)相乘
// 19.9 * 100 = 1989.9999999999998
// 19.9 * 10 * 10 = 1990
// 1306377.64 * 100 = 130637763.99999999
// 1306377.64 * 10 * 10 = 130637763.99999999
// 0.7 * 180 = 125.99999999999999

// 4. 不一樣的數(shù)卻相等
// 1000000000000000128 === 1000000000000000129

計(jì)算機(jī)的底層實(shí)現(xiàn)就無(wú)法完全精確表示一個(gè)無(wú)限循環(huán)的數(shù),而且能夠存儲(chǔ)的位數(shù)也是有限制的,所以在計(jì)算過(guò)程中只能舍去多余的部分,得到一個(gè)盡可能接近真實(shí)值的數(shù)字表示,于是造成了這種計(jì)算誤差。

比如在 JavaScript 中計(jì)算0.1 + 0.2時(shí),十進(jìn)制的0.1和0.2都會(huì)被轉(zhuǎn)換成二進(jìn)制,但二進(jìn)制并不能完全精確表示轉(zhuǎn)換結(jié)果,因?yàn)榻Y(jié)果是無(wú)限循環(huán)的。

// 百度進(jìn)制轉(zhuǎn)換工具
0.1 -> 0.0001100110011001...
0.2 -> 0.0011001100110011...

In JavaScript, Number is a numeric data type in the double-precision 64-bit floating point format (IEEE 754). In other programming languages different numeric types can exist, for examples: Integers, Floats, Doubles, or Bignums.

根據(jù) MDN這段關(guān)于Number的描述 可以得知,JavaScript 里的數(shù)字是采用 IEEE 754 標(biāo)準(zhǔn)的 64 位雙精度浮點(diǎn)數(shù)。該規(guī)范定義了浮點(diǎn)數(shù)的格式,最大最小范圍,以及超過(guò)范圍的舍入方式等規(guī)范。所以只要不超過(guò)這個(gè)范圍,就不會(huì)存在舍去,也就不會(huì)存在精度問(wèn)題了。比如:

// Number.MAX_SAFE_INTEGER 是 JavaScript 里能表示的最大的數(shù)了,超出了這個(gè)范圍就不能保證計(jì)算的準(zhǔn)確性了
var num = Number.MAX_SAFE_INTEGER;
num + 1 === num +2 // = true

實(shí)際工作中我們也用不到這么大的數(shù)或者是很小的數(shù),也應(yīng)該盡量把這種對(duì)精度要求高的計(jì)算交給后端去計(jì)算,因?yàn)楹蠖擞谐墒斓膸?kù)來(lái)解決這個(gè)計(jì)算問(wèn)題。前端雖然也有類似的庫(kù),但是前端引入一個(gè)這樣的庫(kù)代價(jià)太大了。

mathjs

decimal.js

排除直接使用的數(shù)太大或太小超出范圍,出現(xiàn)這種問(wèn)題的情況基本是浮點(diǎn)數(shù)的小數(shù)部分在轉(zhuǎn)成二進(jìn)制時(shí)丟失了精度,所以我們可以將小數(shù)部分也轉(zhuǎn)換成整數(shù)后再計(jì)算。網(wǎng)上很多帖子貼出的解決方案就是這種:

var num1 = 0.1
var num2 = 0.2
(num1 * 10 + num2 * 10) / 10 // = 0.3

但是這樣轉(zhuǎn)換整數(shù)的方式也是一種浮點(diǎn)數(shù)計(jì)算,在轉(zhuǎn)換的過(guò)程中就可能存在精度問(wèn)題,比如:

1306377.64 * 10 // = 13063776.399999999
1306377.64 * 100 // = 130637763.99999999
var num1 = 2.22;
var num2 = 0.1;
(num1 * 10 + num2 * 10) / 10 // = 2.3200000000000003

所以不要直接通過(guò)計(jì)算將小數(shù)轉(zhuǎn)換成整數(shù),我們可以通過(guò)字符串操作,移動(dòng)小數(shù)點(diǎn)的位置來(lái)轉(zhuǎn)換成整數(shù),最后再同樣通過(guò)字符串操作轉(zhuǎn)換回小數(shù):

/**
 * 通過(guò)字符串操作將一個(gè)數(shù)放大或縮小指定倍數(shù)
 * @num 被轉(zhuǎn)換的數(shù)
 * @m   放大或縮小的倍數(shù),為正表示小數(shù)點(diǎn)向右移動(dòng),表示放大;為負(fù)反之
 */
function numScale(num, m) {
  // 拆分整數(shù)、小數(shù)部分
  var parts = num.toString().split(".");
  // 原始值的整數(shù)位數(shù)
  const integerLen = parts[0].length;
  // 原始值的小數(shù)位數(shù)
  const decimalLen = parts[1] ? parts[1].length : 0;
  
  // 放大,當(dāng)放大的倍數(shù)比原來(lái)的小數(shù)位大時(shí),需要在數(shù)字后面補(bǔ)零
  if (m > 0) {
    // 補(bǔ)多少個(gè)零:m - 原始值的小數(shù)位數(shù)
    let zeros = m - decimalLen;
    while (zeros > 0) {
      zeros -= 1;
      parts.push(0);
    }
  // 縮小,當(dāng)縮小的倍數(shù)比原來(lái)的整數(shù)位大時(shí),需要在數(shù)字前面補(bǔ)零
  } else {
    // 補(bǔ)多少個(gè)零:m - 原始值的整數(shù)位數(shù)
    let zeros = Math.abs(m) - integerLen;
    while (zeros > 0) {
      zeros -= 1;
      parts.unshift(0);
    }
  }

  // 小數(shù)點(diǎn)位置,也是整數(shù)的位數(shù): 
  //    放大:原始值的整數(shù)位數(shù) + 放大的倍數(shù)
  //    縮?。涸贾档恼麛?shù)位數(shù) - 縮小的倍數(shù)
  var index = integerLen + m;
  // 將每一位都拆到數(shù)組里,方便插入小數(shù)點(diǎn)
  parts = parts.join("").split("");
  // 當(dāng)為縮小時(shí),因?yàn)榭赡軙?huì)補(bǔ)零,所以使用原始值的整數(shù)位數(shù)
  // 計(jì)算出的小數(shù)點(diǎn)位置可能為負(fù),這個(gè)負(fù)數(shù)應(yīng)該正好是補(bǔ)零的
  // 個(gè)數(shù),所以小數(shù)點(diǎn)位置應(yīng)該為 0
  parts.splice(index > 0 ? index : 0, 0, ".");

  return parseFloat(parts.join(""));
}
/**
 * 獲取小數(shù)位數(shù)
 */
function getExponent(num) {
  return Math.floor(num) === num ?
    0 : num.toString().split(".")[1].length;
}

/**
 * 兩數(shù)相加
 */
function accAdd(num1, num2) {
  const multiple = Math.max(getExponent(num1), getExponent(num2));
  return numScale(numScale(num1, multiple) + numScale(num2, multiple), multiple * -1);
}

測(cè)試用例:

describe("accAdd", function() {
  it("(0.1, 0.2) = 0.3", function() {
    assert.strictEqual(0.3, _.accAdd(0.1, 0.2))
  })
  it("(2.22, 0.1) = 2.32", function() {
    assert.strictEqual(2.32, _.accAdd(2.22, 0.1))
  })
  it("(11, 11) = 22", function() {
    assert.strictEqual(22, _.accAdd(11, 11))
  })
})

代碼地址:https://github.com/xiaoyann/b...

https://developer.mozilla.org...

JavaScript 中小數(shù)和大整數(shù)的精度丟失

JavaScript 中的數(shù)字

計(jì)算機(jī)是怎么存儲(chǔ)數(shù)字的

為什么0.1無(wú)法被二進(jìn)制小數(shù)精確表示?

為什么0.1+0.2=0.30000000000000004而1.1+2.2=3.3000000000000003?

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

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

相關(guān)文章

  • 從一個(gè) bug 看 javascript精度丟失問(wèn)題

    摘要:就像一些無(wú)理數(shù)不能有限表示,如圓周率,等。遵循規(guī)范,采用雙精度存儲(chǔ),占用。參考中不會(huì)失去精度的最大值數(shù)字精度丟失的一些典型問(wèn)題 問(wèn)題描述 后端返回 { spaceObject: { objectId: 1049564069045993472 } } 前端模版,使用的是 atpl 模版 前端獲取 objectId 的方式,const objectId = $(#test).da...

    NusterCache 評(píng)論0 收藏0
  • 探尋 JavaScript 精度問(wèn)題以及解決方案

    摘要:推導(dǎo)為何等于在中所有數(shù)值都以標(biāo)準(zhǔn)的雙精度浮點(diǎn)數(shù)進(jìn)行存儲(chǔ)的。先來(lái)了解下標(biāo)準(zhǔn)下的雙精度浮點(diǎn)數(shù)。精度位總共是,因?yàn)橛每茖W(xué)計(jì)數(shù)法表示,所以首位固定的就沒(méi)有占用空間。驗(yàn)證完成的最大安全數(shù)是如何來(lái)的根據(jù)雙精度浮點(diǎn)數(shù)的構(gòu)成,精度位數(shù)是。 閱讀完本文可以了解到 0.1 + 0.2 為什么等于 0.30000000000000004 以及 JavaScript 中最大安全數(shù)是如何來(lái)的。 十進(jìn)制小數(shù)轉(zhuǎn)為二...

    YanceyOfficial 評(píng)論0 收藏0
  • [ JS 基礎(chǔ) ] JS 浮點(diǎn)數(shù)四則運(yùn)算精度丟失問(wèn)題 (3)

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

    hoohack 評(píng)論0 收藏0
  • 「干貨」細(xì)說(shuō) Javascript 中的浮點(diǎn)數(shù)精度丟失問(wèn)題(內(nèi)附好課推薦)

    摘要:前言最近,朋友問(wèn)了我這樣一個(gè)問(wèn)題在中的運(yùn)算結(jié)果,為什么是這樣的雖然我告訴他說(shuō),這是由于浮點(diǎn)數(shù)精度問(wèn)題導(dǎo)致的。由于可以用階碼移動(dòng)小數(shù)點(diǎn),因此稱為浮點(diǎn)數(shù)。它的實(shí)現(xiàn)遵循標(biāo)準(zhǔn),使用位精度來(lái)表示浮點(diǎn)數(shù)。 showImg(https://segmentfault.com/img/remote/1460000018981071); 前言 最近,朋友 L 問(wèn)了我這樣一個(gè)問(wèn)題:在 chrome 中的運(yùn)算...

    senntyou 評(píng)論0 收藏0
  • 數(shù)據(jù)精度問(wèn)題自查手冊(cè)

    摘要:前言在數(shù)據(jù)敏感的業(yè)務(wù)場(chǎng)景中,常常會(huì)碰到數(shù)據(jù)精度問(wèn)題,尤其在金額顯示占比統(tǒng)計(jì)等地方,該問(wèn)題尤為顯著。計(jì)算機(jī)原理真香數(shù)值的精度問(wèn)題,其實(shí)是非?;A(chǔ)的計(jì)算機(jī)原理知識(shí)。前言 在數(shù)據(jù)敏感的業(yè)務(wù)場(chǎng)景中,常常會(huì)碰到數(shù)據(jù)精度問(wèn)題,尤其在金額顯示、占比統(tǒng)計(jì)等地方,該問(wèn)題尤為顯著。由于數(shù)據(jù)的每一位有效數(shù)字都包含真實(shí)的業(yè)務(wù)語(yǔ)義,一點(diǎn)點(diǎn)偏差甚至可能影響業(yè)務(wù)決策,這讓問(wèn)題的嚴(yán)重性上升了幾個(gè)階梯。 那,什么是精度丟失...

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

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

0條評(píng)論

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