基于bignumber.js简单解决js的精度问题_封装bignumber.js_js中使用简单运算
2024-11-20 15:53:37
一种利用bignumber.js库处理JavaScript中常见浮点数精度问题的简便方法。详细介绍了如何在实际编程中应用以解决精度问题,帮助开发者在日常开发中更有效的处理精度问题。
430
在 JavaScript 中进行十进制运算时,由于 JavaScript 内置的数字类型是双精度浮点数,可能会遇到精度丢失的问题。对于需要更高精度的金融计算、科学计算或其他特殊需求,BigNumber.js
可以提供更好的解决方案
BigNumber.js 是一个强大而灵活的库,用于进行高精度十进制运算。通过使用 BigNumber 对象,你可以避免 JavaScript 中浮点数精度丢失的问题,进行更准确的数学计算。根据你的具体需求,你可以进一步探索 BigNumber.js 的其他功能和方法。
- 安装和引入 BigNumber.js:
你可以通过 npm
或直接下载 BigNumber.js 文件来使用它。在代码中使用 require()
或 <script>
标签来引入库。
npm install bignumber.js --save
- 创建和使用 BigNumber 对象:
使用 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')