| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- package utils
- import (
- "fmt"
- "strconv"
- "strings"
- "unicode"
- )
- // EvaluateFormula calculates the result of a mathematical formula with variable 'x'
- // Supported operators: +, -, *, /
- // Supported grouping: ( )
- func EvaluateFormula(formula string, x float64) (float64, error) {
- if strings.TrimSpace(formula) == "" {
- return x, nil
- }
- postfix, err := infixToPostfix(formula)
- if err != nil {
- return 0, err
- }
- return evaluatePostfix(postfix, x)
- }
- func infixToPostfix(formula string) ([]string, error) {
- var output []string
- var stack []string // operator stack
- i := 0
- for i < len(formula) {
- char := formula[i]
- if unicode.IsSpace(rune(char)) {
- i++
- continue
- }
- // Number or Variable 'x'
- if unicode.IsDigit(rune(char)) || char == '.' || char == 'x' || char == 'X' {
- start := i
- if char == 'x' || char == 'X' {
- output = append(output, "x")
- i++
- } else {
- for i < len(formula) && (unicode.IsDigit(rune(formula[i])) || formula[i] == '.') {
- i++
- }
- output = append(output, formula[start:i])
- }
- continue
- }
- // Operators
- if isOperator(char) {
- for len(stack) > 0 && isOperator(stack[len(stack)-1][0]) && precedence(stack[len(stack)-1][0]) >= precedence(char) {
- output = append(output, stack[len(stack)-1])
- stack = stack[:len(stack)-1]
- }
- stack = append(stack, string(char))
- i++
- continue
- }
- // Parentheses
- if char == '(' {
- stack = append(stack, "(")
- i++
- continue
- }
- if char == ')' {
- for len(stack) > 0 && stack[len(stack)-1] != "(" {
- output = append(output, stack[len(stack)-1])
- stack = stack[:len(stack)-1]
- }
- if len(stack) == 0 {
- return nil, fmt.Errorf("mismatched parentheses")
- }
- stack = stack[:len(stack)-1] // pop '('
- i++
- continue
- }
- return nil, fmt.Errorf("invalid character: %c", char)
- }
- for len(stack) > 0 {
- if stack[len(stack)-1] == "(" {
- return nil, fmt.Errorf("mismatched parentheses")
- }
- output = append(output, stack[len(stack)-1])
- stack = stack[:len(stack)-1]
- }
- return output, nil
- }
- func evaluatePostfix(postfix []string, x float64) (float64, error) {
- var stack []float64
- for _, token := range postfix {
- if token == "x" || token == "X" {
- stack = append(stack, x)
- } else if val, err := strconv.ParseFloat(token, 64); err == nil {
- stack = append(stack, val)
- } else {
- // Operator
- if len(stack) < 2 {
- return 0, fmt.Errorf("invalid expression")
- }
- b := stack[len(stack)-1]
- a := stack[len(stack)-2]
- stack = stack[:len(stack)-2]
- var res float64
- switch token {
- case "+":
- res = a + b
- case "-":
- res = a - b
- case "*":
- res = a * b
- case "/":
- if b == 0 {
- return 0, fmt.Errorf("division by zero")
- }
- res = a / b
- default:
- return 0, fmt.Errorf("unknown operator: %s", token)
- }
- stack = append(stack, res)
- }
- }
- if len(stack) != 1 {
- return 0, fmt.Errorf("invalid expression result")
- }
- return stack[0], nil
- }
- func isOperator(c byte) bool {
- return c == '+' || c == '-' || c == '*' || c == '/'
- }
- func precedence(c byte) int {
- switch c {
- case '+', '-':
- return 1
- case '*', '/':
- return 2
- }
- return 0
- }
|