欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中小數(shù)點(diǎn)精度丟失的原因以及解決方法

 更新時(shí)間:2023年10月18日 09:10:49   作者:你臉上長(zhǎng)麻子  
計(jì)算機(jī)再大的內(nèi)存它也存不下,所以不能存儲(chǔ)一個(gè)相對(duì)于數(shù)學(xué)來(lái)說(shuō)的值,只能存儲(chǔ)一個(gè)近似值,所以當(dāng)計(jì)算機(jī)存儲(chǔ)后再取出來(lái)用時(shí)就會(huì)出現(xiàn)精度問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于JavaScript中小數(shù)點(diǎn)精度丟失的原因以及解決方法,需要的朋友可以參考下

一、為什么會(huì)出現(xiàn)計(jì)算精度丟失的問(wèn)題?

JavaScript中存在小數(shù)點(diǎn)精度丟失的問(wèn)題是由于其使用的浮點(diǎn)數(shù)表示方式。JavaScript采用的是雙精度浮點(diǎn)數(shù)表示法,也稱為IEEE 754標(biāo)準(zhǔn),它使用64位來(lái)表示一個(gè)數(shù)字,其中52位用于表示有效數(shù)字,而其他位用于表示符號(hào)、指數(shù)和特殊情況。

由于使用有限的位數(shù)來(lái)表示無(wú)限的小數(shù),JavaScript無(wú)法準(zhǔn)確地表示某些小數(shù)。其中一個(gè)典型的示例是0.1,它在二進(jìn)制中是一個(gè)無(wú)限循環(huán)的小數(shù)。當(dāng)我們將0.1這樣的小數(shù)轉(zhuǎn)換為二進(jìn)制進(jìn)行存儲(chǔ)時(shí),存在近似表示的誤差,因此在進(jìn)行計(jì)算時(shí)會(huì)出現(xiàn)精度丟失的問(wèn)題。
例如,執(zhí)行以下計(jì)算:

0.1 + 0.2

預(yù)期的結(jié)果應(yīng)該是0.3,但在JavaScript中實(shí)際得到的結(jié)果是0.30000000000000004。這是因?yàn)?.1和0.2無(wú)法以精確的二進(jìn)制形式表示,導(dǎo)致小數(shù)點(diǎn)精度丟失。

這種精度丟失是浮點(diǎn)數(shù)表示法的固有特性,并不僅限于JavaScript,其他編程語(yǔ)言也可能面臨類似的問(wèn)題。因此,在進(jìn)行精確計(jì)算時(shí),特別是涉及到貨幣、金融等方面的計(jì)算,應(yīng)使用其它精確計(jì)算的方法,例如使用整數(shù)進(jìn)行運(yùn)算或使用專門的精確計(jì)算庫(kù)。

總而言之,小數(shù)點(diǎn)精度丟失的問(wèn)題是由于JavaScript使用的浮點(diǎn)數(shù)表示法的特性所致,需要在開(kāi)發(fā)中注意,并考慮使用其他方法或工具來(lái)解決精度問(wèn)題。

二、代碼示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        var floatObj = function () {
            // 判斷傳入的值-是否為整數(shù)
            function isInteger(obj) {
                return Math.floor(obj) === obj
            }
            // 將一個(gè)浮點(diǎn)數(shù)轉(zhuǎn)成整數(shù),返回整數(shù)和倍數(shù)。如 3.14 >> 314,倍數(shù)是 100
            // @param floatNum { number } 小數(shù)
            // @return { object }
            // { times: 100, num: 314 }
            // 用于返回整數(shù)和倍數(shù)
            function toInteger(floatNum) {
                // 聲明一個(gè)對(duì)象用來(lái)保存倍數(shù)和整數(shù)
                var ret = { times: 1, num: 0 }
                // 第一種情況:是整數(shù)
                if (isInteger(floatNum)) {
                    // 把整數(shù)給 ret中的   num
                    ret.num = floatNum
                    return ret //  最后返回 ret
                }
                // 第二種情況-不是整數(shù),
                var strfi = floatNum + ''  // 轉(zhuǎn)為字符串  "0.1"
                var dotPos = strfi.indexOf('.')  // 查詢小數(shù)點(diǎn)
                var len = strfi.substr(dotPos + 1).length; //  獲取小數(shù)點(diǎn)后的長(zhǎng)度
                var times = Math.pow(10, len)  // 放大多少倍
                var intNum = Number(floatNum.toString().replace('.', ''))  // 返回 轉(zhuǎn)為字符串  截取掉小數(shù)點(diǎn)  最后轉(zhuǎn)為數(shù)字(整數(shù))
                // 把獲取到的倍數(shù)和整數(shù)存入對(duì)象中
                ret.times = times
                ret.num = intNum
                return ret
            }
            // 核心方法,實(shí)現(xiàn)加減乘除運(yùn)算,確保不丟失精度
            // 思路:把小數(shù)放大為整數(shù)(乘),進(jìn)行算術(shù)運(yùn)算,再縮小為小數(shù)(除)
            // @param a { number } 運(yùn)算數(shù)1
            // @param b { number } 運(yùn)算數(shù)2
            // @param digits { number } 精度,保留的小數(shù)點(diǎn)數(shù),比如 2, 即保留為兩位小數(shù)
            // @param op { string } 運(yùn)算類型,有加減乘除(add / subtract / multiply / divide)
            function operation(a, b, digits, op) {
                // 獲取倍數(shù)和整數(shù)的對(duì)象
                var o1 = toInteger(a)
                var o2 = toInteger(b)
                // 提取整數(shù)
                var n1 = o1.num
                var n2 = o2.num
                // 提取倍數(shù)
                var t1 = o1.times
                var t2 = o2.times
                // 獲取最大倍數(shù)
                var max = t1 > t2 ? t1 : t2
                var result = null  //
                switch (op) {
                    case 'add':
                        if (t1 === t2) { // 兩個(gè)小數(shù)位數(shù)相同
                            result = n1 + n2    //  
                        } else if (t1 > t2) { // o1 小數(shù)位 大于 o2
                            result = n1 + n2 * (t1 / t2)
                        } else { // o1 小數(shù)位 小于 o2
                            result = n1 * (t2 / t1) + n2
                        }
                        return result / max
                    case 'subtract':
                        if (t1 === t2) {
                            result = n1 - n2
                        } else if (t1 > t2) {
                            result = n1 - n2 * (t1 / t2)
                        } else {
                            result = n1 * (t2 / t1) - n2
                        }
                        return result / max
                    case 'multiply':
                        result = (n1 * n2) / (t1 * t2)
                        return result
                    case 'divide':
                        result = (n1 / n2) * (t2 / t1)
                        return result
                }
            }
            // 加減乘除的四個(gè)接口
            function add(a, b, digits) {
                return operation(a, b, digits, 'add')
            }
            function subtract(a, b, digits) {
                return operation(a, b, digits, 'subtract')
            }
            function multiply(a, b, digits) {
                return operation(a, b, digits, 'multiply')
            }
            function divide(a, b, digits) {
                return operation(a, b, digits, 'divide')
            }
            return {
                add: add,
                subtract: subtract,
                multiply: multiply,
                divide: divide
            }
        }();
        // console.log(floatObj.add(0.5, 0.2))
        console.log(floatObj.add(0.12, 0.3))
    </script>
</head>
<body>
</body>
</html>

三、解決思路

解決方法:

1.首先封裝一個(gè)函數(shù),這個(gè)函數(shù)是用來(lái)判斷單價(jià)是否為一個(gè)整數(shù)。

2.然后在封裝第二個(gè)函數(shù),這個(gè)函數(shù)的作用是返回整數(shù)和倍數(shù)的。

同時(shí)聲明一個(gè)對(duì)象ret來(lái)保存這個(gè)倍數(shù)和整數(shù),

第一種情況就是單價(jià)傳過(guò)來(lái)時(shí)就是整數(shù),那么他的倍數(shù)也就為1, 所以我們可以直接存儲(chǔ)到聲明的對(duì)象中

第二種情況就是當(dāng)單價(jià)傳過(guò)來(lái)時(shí)是浮點(diǎn)數(shù),這時(shí)候我們就要做處理,

(1)、將傳遞過(guò)來(lái)的參數(shù)轉(zhuǎn)為字符串(隱式轉(zhuǎn)換),  

(2)、使用indexOf找到小數(shù)點(diǎn)'.',

(3)、使用substr字符串方法截取小數(shù)點(diǎn)后的長(zhǎng)度length,

(4)、聲明一個(gè)為倍數(shù)的變量Time,同時(shí)使用Math.pow(10, 上一步截取的長(zhǎng)度),   這個(gè)time就是倍數(shù),小數(shù)點(diǎn)后每多一位就會(huì)為10×長(zhǎng)度的次方,再將浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù)(tostring轉(zhuǎn)為字符, 使用replace將小數(shù)點(diǎn)替換為空,再用Number將字符串轉(zhuǎn)為數(shù)字)

最后將獲取到的倍數(shù)和整數(shù)存入對(duì)象中即可

3.最后實(shí)現(xiàn)加減乘除運(yùn)算,確保不丟失精度         

主要思路:把小數(shù)放大為整數(shù)(乘),進(jìn)行算術(shù)運(yùn)算,再縮小為小數(shù)(除)

再次封裝一個(gè)為實(shí)現(xiàn)運(yùn)算的函數(shù)這個(gè)函數(shù)接受三個(gè)參數(shù)(運(yùn)算數(shù)1,運(yùn)算數(shù)2, '加減乘除四個(gè)方法的函數(shù)'),

聲明n1, n2, 分別為單價(jià)1, 單價(jià)2,

聲明t1, t2.為單價(jià)1的倍數(shù)和單價(jià)2的倍數(shù)

再獲取最大倍數(shù)max(使用三元運(yùn)算符),

使用switch判斷條件就是('加減乘除四個(gè)方法的函數(shù)')搭配Case判斷

加法: 三種狀況

1.t1和t2相同的情況下,就是兩個(gè)小數(shù)的位數(shù)相同情況下直接返回n1 + n2 就是整數(shù)相加

2.t1大于t2的情況下 第一個(gè)小數(shù)位數(shù)大于第二位返回, n1 + n2 * (t1 / t2):

3.t1小于t2的情況下 第一個(gè)小數(shù)位數(shù)小于第二位返回, n1 * (t2 / t1) + n2

最后無(wú)論走得是哪一種情況結(jié)果都要除以max(最大倍數(shù))

減法: 三種狀況

1.t1和t2相同的情況下,就是兩個(gè)小數(shù)的位數(shù)相同情況下直接返回n1 - n2 就是整數(shù)相減

2.t1大于t2的情況下 第一個(gè)小數(shù)位數(shù)大于第二位返回, n1 - n2 * (t1 / t2)

3.t1小于t2的情況下 第一個(gè)小數(shù)位數(shù)小于第二位返回, n1 * (t2 / t1) - n2

最后無(wú)論走得是哪一種情況結(jié)果都要除以max(最大倍數(shù))

乘法: 判斷狀態(tài)時(shí)候結(jié)果的是(n1 × n2)/ (t1 × t2)

除法: 判斷狀態(tài)時(shí)候結(jié)果的是(n1 × n2)/ (t1 × t2)

--- 最后進(jìn)行加減乘除進(jìn)行封裝,return這四個(gè)函數(shù)-- -

四、解決的問(wèn)題

在 JavaScript 中處理小數(shù)點(diǎn)精度可以帶來(lái)以下幾個(gè)好處:

避免精度丟失:JavaScript 使用 IEEE 754 浮點(diǎn)數(shù)標(biāo)準(zhǔn)來(lái)表示數(shù)字,但由于浮點(diǎn)數(shù)存儲(chǔ)的是二進(jìn)制近似值,會(huì)導(dǎo)致一些小數(shù)無(wú)法被準(zhǔn)確表示,從而造成精度丟失。通過(guò)處理小數(shù)點(diǎn)精度,可以減少這種精度丟失的情況,確保計(jì)算結(jié)果的準(zhǔn)確性。

精確計(jì)算金融數(shù)據(jù):在金融領(lǐng)域,小數(shù)點(diǎn)精度非常重要。處理貨幣金額、計(jì)算利率和利息等都需要保持精確的小數(shù)點(diǎn)計(jì)算,以避免數(shù)據(jù)錯(cuò)誤和損失。

避免舍入誤差:當(dāng)進(jìn)行多個(gè)浮點(diǎn)數(shù)計(jì)算時(shí),由于每次計(jì)算都可能存在一定的舍入誤差,累積計(jì)算結(jié)果可能會(huì)與預(yù)期的結(jié)果有所偏差。通過(guò)處理小數(shù)點(diǎn)精度,可以減少舍入誤差的影響,提高計(jì)算的準(zhǔn)確性。

增強(qiáng)數(shù)據(jù)可視化:在圖表和可視化數(shù)據(jù)中,小數(shù)點(diǎn)精度可以提供更精確的數(shù)據(jù)展示。例如,在繪制股票價(jià)格曲線或者科學(xué)實(shí)驗(yàn)數(shù)據(jù)時(shí),小數(shù)點(diǎn)精度可以使得數(shù)據(jù)更加準(zhǔn)確和可信。

總的來(lái)說(shuō),處理小數(shù)點(diǎn)精度可以確保計(jì)算結(jié)果的準(zhǔn)確性,尤其在對(duì)于金融數(shù)據(jù)和需要高精度計(jì)算的場(chǎng)景下,這種處理是非常重要的。

五、二進(jìn)制存儲(chǔ)原理

在JS中不區(qū)分整數(shù)和小數(shù),因?yàn)镴S中天生浮點(diǎn)數(shù)(雙精度),在計(jì)算機(jī)存儲(chǔ)中,雙精度的實(shí)際存儲(chǔ)位數(shù)是52位,由于二進(jìn)制中只有 0 和 1,但52位有時(shí)并不能準(zhǔn)確的表達(dá)小數(shù)點(diǎn)后面的數(shù)字,在十進(jìn)制中有四舍五入,在二進(jìn)制中存在0舍1入,所以當(dāng)52位無(wú)法準(zhǔn)確的表達(dá)出一個(gè)小數(shù)時(shí),就會(huì)產(chǎn)生補(bǔ)位動(dòng)作,數(shù)值偏差就在這時(shí)產(chǎn)生了,這是造成計(jì)算精度問(wèn)題的原因。

總結(jié)

到此這篇關(guān)于JavaScript中小數(shù)點(diǎn)精度丟失的原因以及解決方法的文章就介紹到這了,更多相關(guān)JS小數(shù)點(diǎn)精度丟失內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用js寫了一個(gè)類似php的print_r輸出換行功能

    用js寫了一個(gè)類似php的print_r輸出換行功能

    因?yàn)閜hp的print_r比較好用同時(shí)js卻沒(méi)有這個(gè)功能于是自己就寫了一個(gè),感興趣的你可不要錯(cuò)過(guò)了哈,希望本文對(duì)你提高知識(shí)有所幫助
    2013-02-02
  • JavaScript中的一些實(shí)用小技巧總結(jié)

    JavaScript中的一些實(shí)用小技巧總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于JavaScript中的一些實(shí)用小技巧,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 詳解JavaScript的表達(dá)式與運(yùn)算符

    詳解JavaScript的表達(dá)式與運(yùn)算符

    這篇文章主要介紹了JavaScript的表達(dá)式與運(yùn)算符,需要的朋友可以參考下
    2015-11-11
  • JavaScript 動(dòng)態(tài)添加表格行 使用模板、標(biāo)記

    JavaScript 動(dòng)態(tài)添加表格行 使用模板、標(biāo)記

    在客戶端使用JavaScript動(dòng)態(tài)添加表格行,先到網(wǎng)上找了相關(guān)的資料,發(fā)現(xiàn)有現(xiàn)成做好的組件,發(fā)現(xiàn)它只能夠滿足比較簡(jiǎn)單的要求。
    2009-10-10
  • js電話號(hào)碼驗(yàn)證方法

    js電話號(hào)碼驗(yàn)證方法

    JS電話號(hào)碼驗(yàn)證是比較常的一種驗(yàn)證,下邊給出一個(gè)JavaScript驗(yàn)證電話號(hào)碼的小例子。國(guó)內(nèi)固定電話都是七位或8位的數(shù)字組成的,還可以帶有長(zhǎng)途的區(qū)號(hào)。
    2015-09-09
  • Javascript 加載和執(zhí)行-性能提高篇

    Javascript 加載和執(zhí)行-性能提高篇

    Javascript 在瀏覽器中的性能問(wèn)題,可能是最重要的可用性問(wèn)題;Js的阻塞性 瀏覽器用單一進(jìn)程來(lái)處理UI進(jìn)程和Js的執(zhí)行;不管是內(nèi)嵌的還是外鏈的,下載并立即執(zhí)行 因?yàn)樗锌赡軙?huì)修改頁(yè)面
    2012-12-12
  • JS防抖節(jié)流函數(shù)的實(shí)現(xiàn)與使用場(chǎng)景

    JS防抖節(jié)流函數(shù)的實(shí)現(xiàn)與使用場(chǎng)景

    在行走江湖的過(guò)程中,會(huì)出現(xiàn)很多性能優(yōu)化的問(wèn)題來(lái)讓你手足無(wú)措,那么這篇文章主要給大家介紹了關(guān)于JS防抖節(jié)流函數(shù)的實(shí)現(xiàn)與使用場(chǎng)景,針對(duì)這兩個(gè)問(wèn)題來(lái)為你答疑解惑,需要的朋友可以參考下
    2021-07-07
  • Javascript模擬實(shí)現(xiàn)new原理解析

    Javascript模擬實(shí)現(xiàn)new原理解析

    這篇文章主要介紹了Javascript模擬實(shí)現(xiàn)new原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • JavaScript 生成隨機(jī)數(shù)并自動(dòng)大小排序

    JavaScript 生成隨機(jī)數(shù)并自動(dòng)大小排序

    JavaScript按規(guī)定生成隨機(jī)數(shù),并按指定順序自動(dòng)排序,本例中將生成1——100以內(nèi)的隨機(jī)數(shù),并按照由小到大的順序排列起來(lái)。
    2009-12-12
  • 詳解a++和++a的區(qū)別

    詳解a++和++a的區(qū)別

    搞開(kāi)發(fā)已經(jīng)很久了,一直搞不懂a(chǎn)++和++a到底有所什么不同,后來(lái)通過(guò)查閱相關(guān)資料總結(jié)出一點(diǎn)規(guī)律,下面小編通過(guò)本文給大家介紹
    2017-08-08

最新評(píng)論