123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- 'use strict';
- /**
- *
- * @author Mai
- * @date
- * @version
- */
- ;const zhBaseCalc = (function () {
- const zeroPrecision = 12, mulPrecision = 12, divPrecision = 12;
- function digitLength (num) {
- // 兼容科学计数
- var eSplit = num.toString().split(/[eE]/);
- var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
- return len > 0 ? len : 0;
- }
- function powLength (num) {
- var rs = num.toString();
- if (rs.indexOf('+') > 0) {
- return rs.match(/0*$/g).length();
- } else {
- const eSplit = rs.split(/[eE]/);
- const len = Number(eSplit[1]) - this.digitLength(eSplit[0]);
- return len > 0 ? len : 0;
- }
- }
- function round (num, digit) {
- return Math.round(num * Math.pow(10, digit)) / Math.pow(10, digit);
- }
- function add(num1, num2) {
- var d1 = this.digitLength(num1), d2 = this.digitLength(num2);
- return this.round(num1 + num2, Math.max(d1, d2));
- }
- function sub(num1, num2) {
- var d1 = this.digitLength(num1), d2 = this.digitLength(num2);
- return this.round(num1 - num2, Math.max(d1, d2));
- }
- function mul(num1, num2) {
- return this.round(num1 * num2, mulPrecision);
- }
- function div(num1, num2) {
- return this.round(num1 / num2, divPrecision);
- }
- function isNonZero(num) {
- return num && round(num, zeroPrecision) !== 0;
- }
- return {
- digitLength: digitLength,
- powLength: powLength,
- round: round,
- add: add, sub: sub, mul: mul, div: div,
- isNonZero: isNonZero,
- }
- })();
- /**
- * 计算(四则、舍入) 统一,方便以后置换
- * @type {{add, sub, mul, div, round}}
- */
- const ZhCalc = (function () {
- Decimal.set({precision: 50, defaults: true});
- /**
- * 加法 num1 + num2
- * @param num1
- * @param num2
- * @returns {number}
- */
- function add(num1, num2) {
- //return zhBaseCalc.add(num1 ? num1 : 0, num2 ? num2: 0);
- return num1 ? (num2 ? zhBaseCalc.add(num1, num2) : num1) : num2;
- };
- function sum(array) {
- let result = 0;
- for (const a of array) {
- result = ZhCalc.add(result, a);
- }
- return result;
- }
- /**
- * 减法 num1 - num2
- * @param num1
- * @param num2
- * @returns {number}
- */
- function sub(num1, num2) {
- return zhBaseCalc.sub(num1 ? num1 : 0, num2 ? num2 : 0);
- }
- /**
- * 乘法 num1 * num2
- * @param num1
- * @param num2
- * @returns {*}
- */
- function mul(num1, num2, digit = 6) {
- //return Decimal.mul(num1 ? num1 : 0, num2 ? num2 : 0).toDecimalPlaces(digit).toNumber();
- return (num1 && num2) ? (Decimal.mul(num1, num2).toDecimalPlaces(digit).toNumber()) : 0;
- }
- /**
- * 除法 num1 / num2
- * @param num1 - 被除数
- * @param num2 - 除数
- * @returns {*}
- */
- function div(num1, num2, digit = 6) {
- if (num2 && !checkZero(num2)) {
- //return Decimal.div(num1 ? num1: 0, num2).toDecimalPlaces(digit).toNumber();
- return num1 ? (Decimal.div(num1, num2).toDecimalPlaces(digit).toNumber()) : 0;
- } else {
- return null;
- }
- }
- /**
- * 四舍五入
- * @param {Number} value - 舍入的数字
- * @param {Number} decimal - 要保留的小数位数
- * @returns {*}
- */
- function round(value, decimal) {
- decimal = decimal ? parseInt(decimal) : 0;
- return value ? new Decimal(value).toDecimalPlaces(decimal).toNumber() : null;
- }
- const ExprCalc = {
- /**
- * 判断value是否是四则运算符
- * @param {String} value - 判断字符串
- * @return {Boolean}
- */
- isOperator(value) {
- const operatorString = "+-*/()";
- return operatorString.indexOf(value) > -1;
- },
- /**
- * Rpn解析栈
- * @param exp
- * @returns {Array}
- */
- parse2Rpn(exp) {
- const getPriority = function (value){
- switch(value){
- case '+':
- case '-':
- return 1;
- case '*':
- case '/':
- return 2;
- default:
- return 0;
- }
- };
- const priority = function (o1, o2){
- return getPriority(o1) <= getPriority(o2);
- };
- const inputStack = [];
- const outputStack = [];
- const outputQueue = [];
- for (let i = 0, len = exp.length; i < len; i++) {
- const cur = exp[i];
- if (cur !== ' ' ) {
- inputStack.push(cur);
- }
- }
- let num = '', isNumPre = false, isOperatorPre = false;
- while(inputStack.length > 0){
- const cur = inputStack.shift();
- if (this.isOperator(cur) && !(cur === '-' && !isNumPre)) {
- if (isNumPre) {
- outputQueue.push(parseFloat(num));
- num = '';
- }
- if (cur === '(') {
- outputStack.push(cur);
- } else if (cur === ')') {
- let po = outputStack.pop();
- while (po !== '(' && outputStack.length > 0) {
- outputQueue.push(po);
- po = outputStack.pop();
- }
- if (po !== '(') {
- throw "error: unmatched ()";
- }
- } else {
- while(priority(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0){
- outputQueue.push(outputStack.pop());
- }
- outputStack.push(cur);
- }
- isNumPre = false;
- isOperatorPre = true;
- } else {
- num = num + cur;
- isNumPre = true;
- isOperatorPre = false;
- if (inputStack.length === 0) {
- outputQueue.push(parseFloat(num));
- }
- }
- }
- if (outputStack.length > 0) {
- if (outputStack[outputStack.length - 1] === ')' || outputStack[outputStack.length - 1] === '(') {
- throw "error: unmatched ()";
- }
- while (outputStack.length > 0) {
- outputQueue.push(outputStack.pop());
- }
- }
- return outputQueue;
- },
- /**
- * 计算Rpn解析栈
- * @param rpnQueue
- * @returns {*}
- */
- evalRpn(rpnQueue) {
- const getResult = function (num1, num2, opera) {
- switch (opera) {
- case '+':
- return add(num1, num2);
- case '-':
- return sub(num1, num2);
- case '*':
- return mul(num1, num2, 10);
- case '/':
- return div(num1, num2, 10);
- default:
- throw '参数错误';
- }
- };
- const outputStack = [];
- while(rpnQueue.length > 0){
- const cur = rpnQueue.shift();
- if (!this.isOperator(cur)) {
- outputStack.push(cur);
- } else {
- if (outputStack.length < 2) {
- throw "unvalid stack length";
- }
- const sec = outputStack.pop();
- const fir = outputStack.pop();
- outputStack.push(getResult(fir, sec, cur));
- }
- }
- if (outputStack.length !== 1) {
- throw "unvalid expression";
- } else {
- return outputStack[0];
- }
- },
- /**
- * 解析四则运算字符串并计算
- * @param {String} expr
- * @returns
- */
- calcExprStrRpn(expr) {
- try {
- if (!isNaN(Number(expr))) {
- return Number(expr);
- } else {
- const rpnArr = this.parse2Rpn(expr);
- const result = this.evalRpn(rpnArr);
- return result === Infinity ? null : result;
- }
- } catch (err) {
- return null;
- }
- },
- };
- return {add, sum, sub, mul, div, round, isNonZero: zhBaseCalc.isNonZero, calcExpr: ExprCalc}
- })();
|