big.js和php科学函数封装
php
code
function bc()
{
$argv = func_get_args();
$precision = $argv[1] ?? 2;
bcscale(10);
$string = str_replace(' ', '', '('.$argv[0].')');
$string = preg_replace_callback('/\$([0-9\.]+)/', fn ($matches) => '$argv[$1]', $string);
while (preg_match('/(()?)\(([^\)\(]*)\)/', $string, $match)) {
while (preg_match('/([0-9\.]+)(\^)([0-9\.]+)/', $match[3], $m)
|| preg_match('/([0-9\.]+)([\*\/\%])([0-9\.]+)/', $match[3], $m)
|| preg_match('/([0-9\.]+)([\+\-])([0-9\.]+)/', $match[3], $m)
) {
switch ($m[2]) {
case '+':
$result = bcadd($m[1], $m[3]);
break;
case '-':
$result = bcsub($m[1], $m[3]);
break;
case '*':
$result = bcmul($m[1], $m[3]);
break;
case '/':
$result = bcdiv($m[1], $m[3]);
break;
case '%':
$result = bcmod($m[1], $m[3]);
break;
case '^':
$result = bcpow($m[1], $m[3]);
break;
}
$match[3] = str_replace($m[0], $result, $match[3]);
}
if (!empty($match[1]) && function_exists($func = 'bc'.$match[1])) {
$match[3] = $func($match[3]);
}
$string = str_replace($match[0], $match[3], $string);
}
return round((float) $string, $precision);
}
test
js
code
var bc = formulas => { // 传递字符串 执行big计算
formulas = `(${formulas})`
formulas = formulas.replaceAll(' ','')
const regex = {
bracketRegex: /(()?)\(([^\)\(]*)\)/, // 括号的内容
numberRegex: /([0-9\.]+)([\+\-\*\/\%])([0-9\.]+)/ // 两数和运算符
}
const result = {
bracket: null, // 括号的内容匹配结果
number: null, // 两数内容匹配结构
result:'', // 两数计算的结果
bracket_str: '' // 两数计算的公式字符串 如: 1*2
}
while ( result.bracket = regex.bracketRegex.exec(formulas) ) {
result.bracket_str = result.bracket[3] // 括号内的字符串
while ( // 从公式提取两数之间的计算
result.number = regex.numberRegex.exec(result.bracket_str)
) {
const first_number = result.number[1] // 第一个数
const operator = result.number[2] // 运算符
const second_number = result.number[3] // 第二个数
switch (operator) {
case '+':
result.result = Number(first_number) + Number(second_number)
break;
case '-':
result.result = first_number - second_number
break;
case '*':
result.result = first_number * second_number
break;
case '/':
result.result = first_number / second_number
break;
case '%':
result.result = first_number % second_number
break;
// 异或可继续扩展
}
// 两数计算的结束 替换成 结果 `
result.bracket_str = result.bracket_str.replace(result.number[0],result.result)
}
// 括号内部计算结束 替换为结果
formulas = formulas.replace(result.bracket[0],result.bracket_str)
}
return formulas
}
test
big.js
code
import Big from 'big.js'
// import { getConfig } from '@/utils/localStorage'
const getConfig = () => ({
price_precise: 4 // 准确度
})
export default class {
private static instance: any
private precis:number
constructor (precise:number) {
this.precis = precise
}
public static that () { // 当前实例
if (!this.instance) {
const config:any = getConfig()
this.instance = new this(config.price_precise) // config.price_precise为精准度
}
return this.instance
}
// 当需要重新加载时 删除当前实例
public static delInstance () {
this.instance = undefined
}
public init (val:Number) { // 初始化数字
return val.toFixed(this.precis)
}
public bc (formulas:string, precise = null) : string { // 传递字符串 执行big计算
formulas = `(${formulas})`
formulas = formulas.replaceAll(' ', '')
const regex = {
bracketRegex: /(()?)\(([^\)\(]*)\)/, // 括号的内容
numberRegex: /([0-9\.]+)([\+\-\*\/\%])([0-9\.]+)/ // 两数和运算符 负数有bug 见最底下
}
const result:any = {
bracket: null, // 括号的内容匹配结果
number: null, // 两数内容匹配结构
result: '', // 两数计算的结果
bracket_str: '' // 两数计算的公式字符串 如: 1*2
}
// eslint-disable-next-line no-cond-assign
while (result.bracket = regex.bracketRegex.exec(formulas)) {
result.bracket_str = result.bracket[3] // 括号内的字符串
while ( // 从公式提取两数之间的计算
// eslint-disable-next-line no-cond-assign
result.number = regex.numberRegex.exec(result.bracket_str)
) {
const firstNumber = result.number[1] // 第一个数
const operator = result.number[2] // 运算符
const secondNumber = result.number[3] // 第二个数
const big = Big(firstNumber)
switch (operator) {
case '+':
result.result = big.plus(secondNumber)
break
case '-':
result.result = big.minus(secondNumber)
break
case '*':
result.result = big.times(secondNumber)
break
case '/':
result.result = big.div(secondNumber)
break
case '%':
result.result = big.mod(secondNumber)
break
// 异或可继续扩展
}
// 两数计算的结束 替换成 结果 `
result.bracket_str = result.bracket_str.replace(result.number[0], result.result)
}
// 括号内部计算结束 替换为结果
formulas = formulas.replace(result.bracket[0], result.bracket_str)
}
return precise === null ? Big(formulas).toFixed(this.precis) : Big(formulas).toFixed(precise)
}
}
big.js test
单例使用参考
全局方式:
导出方式:
xxx.js
export const bc = (formulas:any, precise:any = null) => Num.that().bc(formulas, precise)
import { bc } from 'xxx.js'
bc('2 * 2')
后续
php
: 在网上百度抄的
js
: 为了封装 big.js
而写的基础封装,思路参考 php
的。
big.js
: 在 js
的基础,替换成科学计算,也就是 big.js
。
(用ts
写的 , js
项目自行修改)
大家项目规则都不一样,按照自己项目来改吧。
Ps
js
版负数有 bug
, php
没有。
bc('-2+1')
'-3.00' // 正确是 '-1.00'
numberRegex: /([0-9\.]+)([\+\-\*\/\%])([0-9\.]+)/ // 两数和运算符
修改为:
numberRegex: /([-\d\.]+?)([\+\-\*\/\%])([-\d\.]+)/ // 两数和运算符
bc('-2+1')
'-1.00'
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: