1. 程式人生 > >解決js加減乘除運算小數丟失精度的問題

解決js加減乘除運算小數丟失精度的問題

// 解決浮動運算問題,避免小數點後產生多位數和計算精度損失。

class Precision {
  // 乘法
  times (num1, num2, ...others) {
    if (others.length > 0) {
      return this.times(this.times(num1, num2), ...others)
    }
    const num1Changed = this.float2Fixed(num1)
    const num2Changed = this.float2Fixed(num2)
    // 把兩個數的小數位數相加
    
const baseNum = this.digitLength(num1) + this.digitLength(num2) const leftValue = num1Changed * num2Changed this.checkBoundary(leftValue) return leftValue / Math.pow(10, baseNum) } // 精確加法 plus (num1, num2, ...others) { if (others.length > 0) { return this.plus(this.plus(num1, num2), ...others) } const
baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2))) return (this.times(num1, baseNum) + this.times(num2, baseNum)) / baseNum } // 精確減法 minus (num1, num2, ...others) { if (others.length > 0) { return this.minus(this.minus(num1, num2), ...others) } const
baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2))) return (this.times(num1, baseNum) - this.times(num2, baseNum)) / baseNum } // 精確除法 divide (num1, num2, ...others) { if (others.length > 0) { return this.divide(this.divide(num1, num2), ...others) } const num1Change = this.float2Fixed(num1) const num2Change = this.float2Fixed(num2) return this.times(num1Change / num2Change, Math.pow(10, this.digitLength(num2) - this.digitLength(num1))) } // 四捨五入,且保留小數 round (num, ratio) { const base = Math.pow(10, ratio) return this.divide(Math.round(this.times(num, base)), base) } // 把小數轉成整數,支援科學計數法。如果是小數則放大成整數 float2Fixed (num) { if (~num.toString().indexOf('e')) { return Number(num.toString().replace('.', '')) } const dlen = this.digitLength(num) return dlen > 0 ? num * Math.pow(10, dlen) : num } // 獲取當前數小數位的長度(處理科學計數法,本質上處理e-n的情況) digitLength (num) { const eSplit = num.toString().split(/[eE]/) const len = (eSplit[0].split('.')[1]|| '').length - (+ eSplit[1] || 0) return len > 0 ? len : 0 } // 檢測數字是否越界,如果越界給出提示 checkBoundary(num) { if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) { console.log(`${num} is beyond boundary when transfer to integer, the results may not be accurate`) } } } let precision = new Precision() console.log(precision.times(0.1, 0.2, 0.3)) console.log(precision.plus(0.1, 0.2)) console.log(precision.minus(0.1, 0.2)) console.log(precision.divide(0.1, 0.2))