如果两个整数太大,超过了 2^52 - 1 的时候,做加法时,会出现精度损失的现象,这时候可以直接利用js提供bigInt类型来做加法,这里就不再赘述了。我这里是用字符串来输出做加法的结果,通过拆分数字来实现无精度损失的加法运算。具体实现如下:
function sum(a, b, step = 9){
const ar1 = splitNumber(a, step)
const ar2 = splitNumber(b, step)
if (ar1[0] !== ar2[0]) {
if (ar1[0] === '-') return minus(ar2, ar1, step)
else return minus(ar1, ar2)
}
if (ar1[0] === '-') return '-' + plus(ar1, ar2, step)
return plus(ar1, ar2, step)
}
/**
* 做加法,需要注意的是,若是拆分后的字符串以0开头需要在计算结果后补上去
**/
function plus(ar1, ar2, step){
let sum = []
const factor = Math.pow(10, step)
let len1 = ar1.length
let len2 = ar2.length
let len = len1
if (len2 < len) len = len2
let overflow = false
let i = 1
for(i = 1; i< len; i++) {
let rs = parseInt(ar1[i],10) + parseInt(ar2[i],10)
if (overflow) rs++
overflow = rs >= factor
let startsWith0 = false
if (!overflow && (ar1[i].startsWith('0') || ar2[i].startsWith('0'))) {
startsWith0 = true
rs += factor
}
if (overflow || startsWith0) {
sum.push(rs.toString().substr(1))
} else {
sum.push(rs.toString())
}
}
let arr
if (len1 > len2) {
arr = ar1
len = len1
} else if (len2 > len1) {
arr = ar2
len = len2
}
for(let j = i; j < len; j++) {
let rs = arr[j]
if (overflow) {
rs++
}
overflow = rs >= factor
let startsWith0 = false
if (!overflow && arr[j].startsWith('0')) {
startsWith0 = true
rs += factor
}
if (overflow || startsWith0) {
sum.push(rs.toString().substr(1))
} else {
sum.push(rs.toString())
}
}
return sum.reverse().join('')
}
/**
* 做减法。计算的结果需要把数字字符串前面的0去掉
**/
function minus(ar1, ar2, step) {
let sum = []
const factor = Math.pow(10, step)
let len1 = ar1.length
let len2 = ar2.length
let len = len1
if (len2 < len) len = len2
let isNegtive = false
let big = ar1
let small = ar2
if (len1 < len2 || len1 == len2 && ar1[ar1.length - 1] < ar2[ar2.length - 1]) {
isNegtive = true
big = ar2
small = ar1
}
let overflow = false
let i = 1
for(i = 1; i< len; i++) {
let rs = parseInt(big[i],10) - parseInt(small[i],10)
if (overflow) rs--
overflow = rs < 0
if (overflow) {
rs += factor
sum.push(rs.toString().substr(1))
} else {
sum.push(rs.toString())
}
}
for(let j = i, l = big.length; j < l; j++) {
let rs = big[j]
if (overflow) {
rs--
}
overflow = rs < 0
if (overflow) {
rs += factor
sum.push(rs.toString().substr(1))
} else {
sum.push(rs.toString())
}
}
const num = sum.reverse().join('')
return (isNegtive ? '-' : '') + num.replace(/^0+/, '')
}
/**
* step 表示拆分的最小长度。把很大的数字拆分成长度不超过step的值
* 的数字字符串。数组的第一个元素是符号位,即“+”, “-”
**/
function splitNumber(num, stp){
let val = num.toString()
const rs = []
if (val[0] === '-') {
rs.push('-')
val = val.substr(1)
} else {
rs.push('+')
}
let i = val.length - 1
let step = stp > 0 ? stp : 9
while(i>=0) {
i -= step
if (i >= 0) {
rs.push(val.substr(i + 1, step))
} else {
rs.push(val.substr(0, step + i + 1))
}
}
return rs
}
function go() {
const a = 123857457837657242
const b = 832842784782784783333
rs = sum(a, b)
console.log(rs)
}
go()