php高精度计算封装类

63 阅读1分钟

将普通的计算公式转换为高精度计算,可以处理括号的情况

```<?php

namespace fast;

class Math
{
    // 定义高精度四则运算公式计算函数
    public static function precedence($operator)
    {
        switch ($operator) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            case '^':
                return 3;
            default:
                return 0;
        }
    }

    // 将计算公式转换为逆波兰表达式
    public static function convertToReversePolish($expression)
    {
        $output = [];  // 输出队列
        $stack = [];   // 运算符栈

        $expression = str_replace(' ', '', $expression);  // 移除空格
        $operators = ['+', '-', '*', '/', '^'];  // 运算符集合

        $i = 0;
        while ($i < strlen($expression)) {
            $token = $expression[$i];

            if (is_numeric($token)) {
                // 如果是数字,直接加入输出队列
                $number = '';
                while ($i < strlen($expression) && (is_numeric($expression[$i]) || $expression[$i] == '.')) {
                    $number .= $expression[$i];
                    $i++;
                }
                $output[] = $number;
            } elseif (in_array($token, $operators)) {
                // 如果是运算符
                while (!empty($stack) && in_array(end($stack), $operators) && self::precedence(end($stack)) >= self::precedence($token)) {
                    // 从栈中将优先级高于或等于当前运算符的运算符弹出,并加入输出队列
                    $output[] = array_pop($stack);
                }
                $stack[] = $token;  // 当前运算符入栈
                $i++;
            } elseif (
                $token == '('
            ) {
                // 如果是左括号,入栈
                $stack[] = $token;
                $i++;
            } elseif (
                $token == ')'
            ) {
                // 如果是右括号,将栈中的运算符弹出并加入输出队列,直到遇到左括号
                while (!empty($stack) && end($stack) != '(') {
                    $output[] = array_pop($stack);
                }

                if (!empty($stack) && end($stack) == '(') {
                    array_pop($stack);
                }
                $i++;
            } else {
                // 存在无法识别的字符
                return "Invalid character";
            }
        }

        // 将栈中剩余的运算符加入输出队列
        while (!empty($stack)) {
            if (end($stack) == '(') {
                return "Mismatched parentheses";
            }
            $output[] = array_pop($stack);
        }

        return $output;
    }




    // 高精度计算逆波兰表达式
    public static  function calculateReversePolishNotation($expression)
    {
        $stack = [];

        // 遍历逆波兰表达式中的每个元素
        foreach ($expression as $token) {
            if (is_numeric($token)) {
                // 如果是数字,则将其压入栈中
                $stack[] = $token;
            } else {
                // 如果是运算符,则弹出栈顶两个数字进行计算,并将结果压入栈中
                $operand2 = array_pop($stack);
                $operand1 = array_pop($stack);

                switch ($token) {
                    case '+':
                        $result = bcadd($operand1, $operand2, 2);
                        break;
                    case '-':
                        $result = bcsub($operand1, $operand2, 2);
                        break;
                    case '*':
                        $result = bcmul($operand1, $operand2, 2);
                        break;
                    case '/':
                        $result = bcdiv($operand1, $operand2, 2);
                        break;
                    default:
                        return "Invalid operator";
                }

                $stack[] = $result;
            }
        }

        // 返回栈顶元素作为最终结果
        return end($stack);
    }

    // 过滤浮点型数据小数点后面多余的0
    public static function filterDecimal($number)
    {
        $filteredNumber = rtrim($number, '0');
        if ($filteredNumber[strlen($filteredNumber) - 1] == '.') {
            $filteredNumber = rtrim($filteredNumber, '.');
        }
        return $filteredNumber;
    }

    //高精度计算计算
    public static function calcu($expression)
    {
        $res = self::calculateReversePolishNotation(self::convertToReversePolish($expression));
        return $res;
    }
}