Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javascript 实现精度运算 #1

Open
sunhengzhe opened this issue Aug 9, 2017 · 9 comments
Open

javascript 实现精度运算 #1

sunhengzhe opened this issue Aug 9, 2017 · 9 comments

Comments

@sunhengzhe
Copy link
Member

用 js 实现高精度运算,这个问题是老生常谈了。如果真的要前端做一个高精度运算(比如钱),还是要注意这个问题的。

function add (numLeft, numRight){
    // todo
}

ex: add(0.1, 0.2) => 0.3

更一般地,实现四则运算的精度运算

function operation (numLeft, numRight, character){
    // todo
}

ex: operation(0.1, 0.2, '+') => 0.3
@Jiasm
Copy link
Member

Jiasm commented Aug 9, 2017

'use strict'

function add (nLeft, nRight) {

  if (/^\d+$/.test(nLeft) && /^\d+$/.test(nRight)) return +nLeft + +nRight
  
  let reg = /\.(\d*)$/
  
  nLeft = `${nLeft}`
  nRight = `${nRight}`

  if (!reg.test(nLeft)) {
    nLeft = `${nLeft}.`
  } else if (!reg.test(nRight)) {
    nLeft = `${nRight}.`
  }

  let leftLen = nLeft.length
  let rightLen = nRight.length
  let leftDecimalLen = nLeft.match(reg)[1].length
  let leftNumberLen = leftLen - leftDecimalLen
  let rightDecimalLen = nRight.match(reg)[1].length
  let rightNumberLen = rightLen - rightDecimalLen
  let decimalLen = Math.max(leftDecimalLen, rightDecimalLen)
  let maxLen = Math.max(leftLen, rightLen)

  nLeft = nLeft.padEnd(leftNumberLen + decimalLen, 0)
  nRight = nRight.padEnd(rightNumberLen + decimalLen, 0)

  let index = decimalLen
  let result = new Array(decimalLen)
  let temp = new Array(decimalLen).fill(0)
  let leftArr = nLeft.match(/\.(\d+)$/)[1].split('')
  let rightArr = nRight.match(/\.(\d+)$/)[1].split('')
  let overflow = 0

  while (index--) {
    let l = leftArr[index] || 0
    let r = rightArr[index] || 0
    let t = temp[index] || 0

    let num = result[index] = +l + +r + +t

    if (num >= 10) {
      result[index] = num % 10

      num = num / 10 | 0
      if (index === 0) {
        overflow = num
      } else {
        temp[index - 1] = num
      }
    }
  }

  return `${parseInt(nLeft) + parseInt(nRight) + overflow}.${result.join('')}`
}

console.log(add(1, 2))
console.log(add(1, 0.2))
console.log(add(0.1, 0.2))
console.log(add(233333.1, 0.215125125155))

@sunhengzhe
Copy link
Member Author

@Jiasm 取小数位数的正则,如果没有小数位就报错了吧

@TracyCt
Copy link

TracyCt commented Aug 9, 2017

function add(a, b) {
   if((a+'').split('.')[1] && (b+'').split('.')[1]) {
        var num = (a+'').split('.')[1].length > (b+'').split('.')[1].length ? Math.pow(10, (a+'').split('.')[1].length) : Math.pow(10, (b+'').split('.')[1].length);
	return (a*num + b*num)/num
	} else {
	    return a+b
	}
}
console.log(add(1, 2))
console.log(add(1, 0.2))
console.log(add(0.1, 0.2))
console.log(add(233333.1, 0.215125125155))    

保留小数位 toFixed()自行决定

@Jiasm
Copy link
Member

Jiasm commented Aug 9, 2017

@sumodream

你的小数点后边的位数太多,被强转了-.-

这就是为啥选择使用操作字符串,而不是直接 * XXX / XXX

@Jiasm
Copy link
Member

Jiasm commented Aug 9, 2017

@sunhengzhe 已修复

@TracyCt
Copy link

TracyCt commented Aug 9, 2017

@Jiasm 可以 toFixed 啊 我不知道几位 正常要几位用户决定啊

@Jiasm
Copy link
Member

Jiasm commented Aug 9, 2017

@sumodream toFixed最大支持20.

@TracyCt
Copy link

TracyCt commented Aug 9, 2017

@Jiasm 最大值也满足刚才那个需求啊

@Jiasm
Copy link
Member

Jiasm commented Aug 9, 2017

@sumodream 小数点后边位数太多了你的展示会有问题。。。 console.log(add(233333.1, 0.9007199254740991))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants