在 JavaScript 中进行十进制运算时,由于 JavaScript 内置的数字类型是双精度浮点数,可能会遇到精度丢失的问题。对于需要更高精度的金融计算、科学计算或其他特殊需求,BigNumber.js 可以提供更好的解决方案
BigNumber.js 是一个强大而灵活的库,用于进行高精度十进制运算。通过使用 BigNumber 对象,你可以避免 JavaScript 中浮点数精度丢失的问题,进行更准确的数学计算。根据你的具体需求,你可以进一步探索 BigNumber.js 的其他功能和方法。
你可以通过 npm 或直接下载 BigNumber.js 文件来使用它。在代码中使用 require() 或 <script> 标签来引入库。
npm install bignumber.js --save
使用 BigNumber() 构造函数可以创建一个 BigNumber 对象。你可以通过传递一个数字或字符串来初始化这个对象。
import BigNumber from "bignumber.js";
BigNumber 对象支持常见的算术运算,如加法、减法、乘法和除法。你可以使用相应的方法来执行这些运算。
// 加法 BigNumber(1).plus(0,1).toString(); // 减法 BigNumber(1).mimus(1).toString(); // 乘法 BigNumber(1).times(2).toString(); // 除法 BigNumber(1).div(2).toString(); // 取余 BigNumber(1).mod(3).toString(); // 绝对值 BigNumber(1).abs().toString();
BigNumber.js 允许你设置精度参数,以控制运算的精度。
你可以使用 compareTo() 方法来比较两个 BigNumber 对象的大小,也可以使用 equals() 方法来检查两个 BigNumber 对象是否相等。
BigNumber.js 还提供了其他一些方法,如取余数、取整、小数点移动等。
但是使用中方法比较复杂,现在引用了网友的字符串运算符方法
https://www.npmjs.com/package/calc-number
import BigNumber from "bignumber.js";
export function fnBigNumber(runStr) {
let allMethod={
sin:(data)=>Math.sin(data[0]),
cos:(data)=>Math.cos(data[0]),
tan:(data)=>Math.tan(data[0]),
atan:(data)=>Math.atan(data[0]),
}
class runObj {
constructor(type, data) {
this.type = type;
this.data = data.map(v => {
if (v instanceof runObj) {
return v.run();
} else if (v instanceof Array) {
let runObjItem = new runObj(v[1], [v[0], v[2]]);
return runObjItem.run();
} else {
return v;
}
});
}
run() {
if (this.type === '+') {
const temp = new BigNumber(this.data[0])
return temp.plus(this.data[1]).toNumber()
} else if (this.type === '-') {
const temp = new BigNumber(this.data[0])
return temp.minus(this.data[1]).toNumber()
} else if (this.type === '*') {
const temp = new BigNumber(this.data[0])
return temp.multipliedBy(this.data[1]).toNumber()
} else if (this.type === '/') {
const temp = new BigNumber(this.data[0])
return temp.div(this.data[1]).toNumber()
} else if (this.type === '**') {
const temp = new BigNumber(this.data[0])
return temp.pow(this.data[1]).toNumber()
} else if (this.type === 'number') {
return this.data[0];
} else if (allMethod[this.type]) {
return allMethod[this.type](this.data);
}else{
throw new Error('运算类型不存在' + this.type)
}
}
}
const allKeyWord = [
Object.keys(allMethod),
['**'],
['*', '/'],
['+', '-'],
];// 以优先级排列
// 第一步分词
let resultArr = _split(runStr); // '1+2' => ['1', '+', '2']
let aCorrectArr=[];
let _flag=false;//是否是两个运算符想家
resultArr.forEach((e,i)=>{
if(['+', '-', '*', '/'].includes(e)){
if(_flag){
//如果_flag为true 说明上一个也是运算符,则也需要手动push
aCorrectArr.push("0");
_flag=false;
}
if(i==0){
//如果第一个就是运算符 需要手动加一个
aCorrectArr.push("0");
}
//1.如果是运算符就改变flag
_flag=true;
}else{
_flag=false
}
aCorrectArr.push(e)
});
if(['+', '-', '*', '/'].includes(aCorrectArr[aCorrectArr.length-1])){
//如果最后一个是运算符
aCorrectArr.push("0")
}
let slip = 0;
let runObjItem = arrayToRunObjType(aCorrectArr, []);
return runObjItem.run();
function _split(runStr) {
let resultArr = [];
let split = 0;
while (split < runStr.length) {
const match = Object.keys(allMethod).find(v => v === runStr.slice(split, split + v.length));
if (match) {
resultArr.push(runStr.slice(split, split + match.length))
split += 3;
} else if (['**'].includes(runStr.slice(split, split + 2))) {
resultArr.push(runStr.slice(split, split + 2))
split += 2;
} else if (['+', '-', '*', '/', '(', ')'].includes(runStr[split])) {
resultArr.push(runStr[split]);
split++;
} else if (runStr[split].match(/d/)) {
let numberStr = runStr[split];
for (let i = split + 1; i < runStr.length; i++) {
if (runStr[i].match(/d/) || runStr[i] === '.') {
numberStr += runStr[i];
split++;
} else {
break;
}
}
resultArr.push(numberStr)
split++;
} else {
split++;
}
}
return resultArr
}
function arrayToRunObjType(resultArr, endKeyWord = []) {
let temp = [[]];
for (; slip < resultArr.length; slip++) {
const word = resultArr[slip]
if (endKeyWord.includes(word)) {
break;
}
if (word.match(/d+/)) {
temp[temp.length - 1].push(word);
} else if (word === '(') {
slip++;
const result = arrayToRunObjType(resultArr, [')']);
if (resultArr[slip] !== ')') {
throw new Error('结构错误')
}
temp[temp.length - 1].push(result);
} else if (Object.keys(allMethod).includes(word)) {
slip += 2;
const nextObj = arrayToRunObjType(resultArr, [')'])
if (temp[temp.length - 1].length === 0) {
temp[temp.length - 1].push(nextObj)
temp[temp.length - 1].push(word)
} else {
temp[temp.length - 1].push([nextObj, word])
}
if (resultArr[slip] !== ')') {
throw new Error('结构错误')
}
} else if (['**', '*', '/', '+', '-'].includes(word)) {
if (temp[temp.length - 1].length === 1) {
temp[temp.length - 1].push(word);
} else {
const preview = temp[temp.length - 1];
const thisIndex = allKeyWord.findIndex(v => v.includes(word));
const preIndex = allKeyWord.findIndex(v => v.includes(preview[1]))
const allNextKeyword = []
allKeyWord.slice(thisIndex + 1).forEach(v => {
v.forEach(vv => {
allNextKeyword.push(vv)
})
})
if (thisIndex < preIndex || (['**'].includes(word) && thisIndex === preIndex)) { // 本优先级更高进行优先级抢夺,**连自己也会抢夺
slip++;
const nextObj = arrayToRunObjType(resultArr, allNextKeyword)
slip--;
preview[preview.length - 1] = [
preview[preview.length - 1],
word,
nextObj,
]
} else {
temp[temp.length - 1] = [temp[temp.length - 1]]
temp[temp.length - 1].push(word);
}
}
} else {
throw new Error('分词失败' + word)
}
}
if (temp[temp.length - 1].length === 1) {
// 1+2*3/2+2*4
// 1+(2*3/2)+(2*4)
if (typeof temp[temp.length - 1][0] === 'string') {
temp[temp.length - 1] = parseFloat(temp[temp.length - 1][0])
} else {
temp[temp.length - 1] = temp[temp.length - 1][0]
}
}
if (temp.length === 1) {
temp = temp[0]
}
if (typeof temp !== 'number') {
}
let runObjItem;
if (typeof temp === 'number') {
runObjItem = new runObj('number', [temp]);
} else if (['+', '-', '*', '/', '**'].includes(temp[1])) {
runObjItem = new runObj(temp[1], [temp[0], temp[2]]);
} else if (Object.keys(allMethod).includes(temp[1])) {
runObjItem = new runObj(temp[1], [temp[0]]);
} else {
throw new Error('结构不存在' + temp[1])
}
return runObjItem;
}
}
fnBigNumber('1-1')