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

big.js和php科学函数封装

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和php科学函数封装

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

big.js和php科学函数封装

单例使用参考

全局方式:

big.js和php科学函数封装

导出方式:

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 协议》,转载必须注明作者和本文链接
专心学习不瞎搞
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!