luxi-record-utils
Version:
82 lines • 4.43 kB
text/typescript
/*
** 超长数字相加
** 只允许输入字符串,因为数字长度问题会把一些超大数字转化为科学计数法
** 例如: 0.000000000000003 ==> '3e-15'
*/
function numberAdd(a: string, b: string): string {
if (!a || !b) throw new Error('Please enter two strings composed of numbers')
const isReduce = (Number(a) > 0 && Number(b) < 0 || Number(a) < 0 && Number(b) > 0) ? true : false
const isNegative = Number(a) < 0 && Number(b) < 0 ? true : false
let resulet = '', carry = 0
if (isReduce) {
const numberOne = Number(a), numberTwo = Number(b)
const absNumberOne = a.replace('-', ''), absNumberTwo = b.replace('-', '')
const hasMinusSign = (Math.abs(numberOne) > Math.abs(numberTwo) && numberOne < 0) || (Math.abs(numberTwo) > Math.abs(numberOne) && numberTwo < 0) ? true : false
const length = absNumberOne.length
const big = Math.abs(numberOne) > Math.abs(numberTwo) ? absNumberOne : absNumberTwo
const small = Math.abs(numberOne) < Math.abs(numberTwo) ? absNumberOne : absNumberTwo
for (let i = length - 1; i >= 0; i--) {
const numberA = Number(big[i]), numberB = Number(small[i])
const tmp = numberA - numberB - carry
if (tmp < 0) {
carry = 1
resulet = tmp + 10 + resulet
} else {
carry = 0
resulet = tmp + resulet
}
}
resulet = hasMinusSign ? `-${resulet}` : resulet
} else {
const stringOne = isNegative ? a.replace('-', '') : a
const stringTwo = isNegative ? b.replace('-', '') : b
const length = stringOne.length
for (let i = length - 1; i >= 0; i--) {
const numberA = Number(stringOne[i]), numberB = Number(stringTwo[i])
const tmp = numberA + numberB + carry
carry = Math.floor(tmp / 10)
resulet = tmp % 10 + resulet
}
if (carry) resulet = carry + resulet
resulet = isNegative ? `-${resulet}` : resulet
}
return resulet
}
export default function largeNumberAdd(num1: string, num2: string): string {
let stringOne = String(num1), stringTwo = String(num2)
const reg = /^(-?\d+)(\.\d+)?$/ // /^-?\d+$/ 整数 /^0+$/ 全零
if (!reg.test(stringOne) || !reg.test(stringTwo)) {
throw new Error('Please enter a string composed of numbers')
}
const stringOneLess = Number(stringOne) < 0 ? true : false
const stringTwoLess = Number(stringTwo) < 0 ? true : false
const isFloat = stringOne.includes('.') || stringTwo.includes('.')
let pointIndex: number | null = null
if (isFloat) {
let stringOneFloat = stringOne.split('.')[1] || ''
let stringTwoFloat = stringTwo.split('.')[1] || ''
pointIndex = Math.max(stringOneFloat.length, stringTwoFloat.length)
stringOneFloat = stringOneFloat.padEnd(pointIndex, '0')
stringTwoFloat = stringTwoFloat.padEnd(pointIndex, '0')
pointIndex = Number(`-${pointIndex}`)
let stringOneInteger = stringOne.replace('-', '').split('.')[0]
let stringTwoInteger = stringTwo.replace('-', '').split('.')[0]
const maxLength = Math.max(stringOneInteger.length, stringTwoInteger.length)
stringOneInteger = stringOneInteger.padStart(maxLength, '0')
stringTwoInteger = stringTwoInteger.padStart(maxLength, '0')
stringOne = stringOneLess ? `-${stringOneInteger}${stringOneFloat}` : stringOneInteger + stringOneFloat
stringTwo = stringTwoLess ? `-${stringTwoInteger}${stringTwoFloat}` : stringTwoInteger + stringTwoFloat
} else {
let stringOneInteger = stringOne.replace('-', '')
let stringTwoInteger = stringTwo.replace('-', '')
const maxLength = Math.max(stringOneInteger.length, stringTwoInteger.length)
stringOneInteger = stringOneInteger.padStart(maxLength, '0')
stringTwoInteger = stringTwoInteger.padStart(maxLength, '0')
stringOne = stringOneLess ? `-${stringOneInteger}` : stringOneInteger
stringTwo = stringTwoLess ? `-${stringTwoInteger}` : stringTwoInteger
}
console.log(stringOne, stringTwo)
const result = numberAdd(stringOne, stringTwo)
if (pointIndex) return `${result.slice(0, pointIndex)}.${result.slice(pointIndex)}`
return result
}