1. 程式人生 > >【JS】關於js浮點數計算精度不準確問題的解決辦法

【JS】關於js浮點數計算精度不準確問題的解決辦法

在專案中計算商品價格的時候再次遇到js浮點數計算出現誤差的問題,以前一碰到這個問題就用tofixed方法進行處理一下,這對於一個程式設計師來說是及其不嚴謹的。

1、發現問題:

在測試js浮點數進行加減乘除計算時,都可能出現問題,如下:

console.log(0.1 + 0.2);//0.30000000000000004
console.log(1.0 - 0.9);//0.09999999999999998
console.log(19.9 * 100);//1989.9999999999998
console.log(6.6 / 0.2);//32.99999999999999

2、不精準原因:

下面我們來說一下浮點數運算產生誤差的原因:(拿0.1+0.2=0.30000000000000004進行舉例)

首先,我們要站在計算機的角度思考 0.1 + 0.2 這個看似小兒科的問題。我們知道,能被計算機讀懂的是二進位制,而不是十進位制,所以我們先把 0.1 和 0.2 轉換成二進位制看看:  

0.1 => 0.0001 1001 1001 1001…(無限迴圈)

0.2 => 0.0011 0011 0011 0011…(無限迴圈)  

上面我們發現0.1和0.2轉化為二進位制之後,變成了一個無限迴圈的數字,這在現實生活中,無限迴圈我們可以理解,但計算機是不允許無限迴圈的,對於無限迴圈的小數,計算機會進行舍入處理。進行雙精度浮點數的小數部分最多支援 52 位,所以兩者相加之後得到這麼一串 0.0100110011001100110011001100110011001100110011001100 因浮點數小數位的限制而截斷的二進位制數字,這時候,我們再把它轉換為十進位制,就成了 0.30000000000000004。

3、解決辦法:

var floatObj = function () {

        /*
         * 判斷obj是否為一個整數
         */
        function isInteger(obj) {
            return Math.floor(obj) === obj
        }

        /*
         * 將一個浮點數轉成整數,返回整數和倍數。如 3.14 >> 314,倍數是 100
         * @param floatNum {number} 小數
         * @return {object}
         *   {times:100, num: 314}
         */
        function toInteger(floatNum) {
            var ret = {times: 1, num: 0};
            if (isInteger(floatNum)) {
                ret.num = floatNum;
                return ret
            }
            var strfi = floatNum + '';
            var dotPos = strfi.indexOf('.');
            var len = strfi.substr(dotPos + 1).length;
            var times = Math.pow(10, len);
            var intNum = parseInt(floatNum * times + 0.5, 10);
            ret.times = times;
            ret.num = intNum;
            return ret
        }

        /*
         * 核心方法,實現加減乘除運算,確保不丟失精度
         * 思路:把小數放大為整數(乘),進行算術運算,再縮小為小數(除)
         *
         * @param a {number} 運算數1
         * @param b {number} 運算數2
         * @param op {string} 運算型別,有加減乘除(add/subtract/multiply/divide)
         *
         */
        function operation(a, b, op) {
            var o1 = toInteger(a);
            var o2 = toInteger(b);
            var n1 = o1.num;
            var n2 = o2.num;
            var t1 = o1.times;
            var t2 = o2.times;
            var max = t1 > t2 ? t1 : t2;
            var result = null;
            switch (op) {
                case 'add':
                    if (t1 === t2) { // 兩個小數位數相同
                        result = n1 + n2
                    } else if (t1 > t2) { // o1 小數位 大於 o2
                        result = n1 + n2 * (t1 / t2)
                    } else { // o1 小數位 小於 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
            }
        }

        // 加減乘除的四個介面
        function add(a, b) {
            return operation(a, b, 'add')
        }

        function subtract(a, b) {
            return operation(a, b, 'subtract')
        }

        function multiply(a, b) {
            return operation(a, b, 'multiply')
        }

        function divide(a, b) {
            return operation(a, b, 'divide')
        }

        // exports
        return {
            add: add,
            subtract: subtract,
            multiply: multiply,
            divide: divide
        }
    }();

呼叫方法:

console.log(floatObj.add(0.1, 0.2));//0.3
console.log(floatObj.subtract(1.0, 0.9));//0.1
console.log(floatObj.multiply(19.9, 100));//1990
console.log(floatObj.divide(6.6, 0.2));//33

相關推薦

JS關於js點數計算精度準確問題的解決辦法

在專案中計算商品價格的時候再次遇到js浮點數計算出現誤差的問題,以前一碰到這個問題就用tofixed方法進行處理一下,這對於一個程式設計師來說是及其不嚴謹的。 1、發現問題: 在測試js浮點數進行加減乘除計算時,都可能出現問題,如下: console.log(0.1

關於js點數計算精度準確問題的解決辦法

* ** method ** * add / subtract / multiply /divide * * ** explame ** * 0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004) * 0.2 + 0.4 ==

學以致用:手把手教你擼一個工具庫並打包釋出,順便解決JS點數計算精度問題

本文講解的是怎麼實現一個工具庫並打包釋出到npm給大家使用。本文實現的工具是一個分數計算器,大家考慮如下情況: $$ \sqrt{(((\frac{1}{3}+3.5)*\frac{2}{9}-\frac{27}{109})/\frac{889}{654})^4} $$ 這是一個分數計算式,使用JS原生也是可

親歷點數計算精度導致錯誤

v0->v1是一條朝右下的線段,用下面程式碼計算點v3在直線上方還是下方 v0x = -254.923599 v0z = 365.348907 v1x = -249.52359 v1z =

點數計算精度丟失問題#W01

前幾日電話面試,被問到一個問題: “浮點數計算精度丟失的原因是什麼?”啊,啥? 我一臉懵逼,“就是在irb中,0.2+0.4不等於0.6,為什麼?“,面試官又補了一句。我沒有真正get到問題是什麼,胡說了一通。顯然,這是問到了我的知識盲區了,我從來沒有遇到過這個問題。於是我開

點數計算精度控制

進一步除錯我發現,浮點數計算錯誤發生在一個函式(InitEngine)呼叫後,在此函式呼叫前就不會出這個問題。這個函式是一個引擎的初時化函式,無法知道他的具體實現,是什麼原因造成了浮點計算錯誤呢? 編譯選項設定不當?應該不會吧,因為生成的彙編程式碼是正確的呀。在彙編程式碼正確的情況下,浮點計算精度太小,唯一

bugvue-cli 3.0報錯的解決辦法

文件中 分享圖片 not main res idt 說明 exports 修改 先上bug圖片 bug說明:初裝vue_cli3.0寫了個組件,運行錯誤,顯示如圖, 代碼提示:[Vue warn]: You are using the runtime-only bu

Sqlserver通過連結伺服器訪問Oracle的解決辦法

一、建立sqlserver連結服務(sqlserver連結oracle)  首先sqlserver 連結oracle可以通過兩個訪問介面: “MSDAORA” 和“OraOLEDB.Oracle” 1、“MSDAORA”訪問介面是由Microsoft OLE DB Provider for O

SVNSVN錯誤[ locked; try performing 'cleanup']的解決辦法

用Eclipse的svn外掛commit的時候,發生如下異常 Some of selected resources were not committed. svn: Working copy 'C:\project\xxxxx\xxxxx-web\test' locked;

Cuckooadd_path()失敗 和 report.json太大解決辦法

add_path()失敗 >>>from cuckoo.core.database import Database >>>db=Database() >>

java中解決double計算精度準確問題

現象: 因需要對比投資成功前與投資成功後前後的剩餘金額的斷言,在斷言的時候發現針對double型別計算時會出現精度計算問題: 例如使用程式碼如下: 如上圖會因精度導致斷言失敗。 最後使用 DecimalFormat 類將數字進行格式化,程式碼如下: Decimal

LinuxOpencvPython安裝opencv以及無法使用cv2.imshow()解決辦法(Ubuntu14.04)

------【2017.07.14 更新】------------------------------------------------------- 安裝opencv3每次cmake都要下載3rd

Java異常 java.io.IOException: Stream closed 的解決辦法

在程式執行過程中,如果我們遇見了以下異常:java.io.IOException: Stream closed. 即stream已經被關閉,我們分析一下就很容易知道原因了,即stream已經被關閉。那麼最有可能的情況就是你多次關閉了Stream。 例如: try { InputStream is

BUGwin7跑tensorflow_gpu電腦卡機的解決辦法

我的系統是windows7旗艦版,編輯器用的是anaconda的spyder 之前裝了gpu版的tensorflow一跑程式就卡死 讓我各種懷疑人生。。。 直到我把顯示卡驅動更新至最新版本~ 如果電腦可以執行faceworks這個測試程式,就沒問題了 fac

mysqlLinux下mysql資料庫顯示解決全過程

症狀:在mysql下,show databases,僅顯示兩個資料庫,而非全部的資料庫mysql>show databases;  +--------------------+  |Databas

JS計算精度問題分析與解決

href 動態控制 hub 截斷 max fix math floating 方案 問題描述 在JS計算四則運算時會遇到精度丟失的問題,會引起諸多問題,看看以下例子: 例如:在chrome控制臺輸入 0.1 + 0.7 輸出結果是 0.7999999999999999 例如

js處理點數計算誤差

眾所周知,浮點計算會產生舍入誤差的問題,比如,0.1+0.2,結果應該是0.3,但是計算的結果並不是如此,而是0.30000000000000004,這是使用基於IEEE754數值的浮點計算的通病,js並非獨此一家,今天我們就來看看js怎麼解決這個誤差的。 以下是針對加減乘除的解決方法: 加法: functi

js 點數計算誤差解決方法

eg:一個整數*一個小數出現的結果是 計算機程式語言裡浮點數計算會存在精度丟失問題(或稱舍入誤差),其根本原因是二進位制和實現位數限制有些數無法有限表示 * 以下是十進位制小數對應的二進位制表示 * 0.1 >> 0.0001 1001 100

js 中關於點數計算

專案中遇到浮點數的計算,開始想當然的當做int型別去做計算,計算過後才發現並不是如此,於是在網上找到了一個很好的方法 //加法函式 function accAdd(arg1, arg2) {     var r1, r2, m;   &nb

Javascript優化後的加減乘除(解決js點數計算bug)

說明 眾所周知,js在計算浮點數時候,結果可能會不準確。比如:(在chrome中的運算結果) 2.2 + 2.1 = 4.300000000000001 2.2 - 1.9 = 0.30000000000000027 2.2 * 2.2 = 4.84