数据上报
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
4.3 KiB

package utils
import (
"fmt"
"math"
"strconv"
"strings"
"unicode"
)
func CalculateFormula(formulaExpression string) float64 {
formulaExpression = strings.Replace(formulaExpression, " ", "", -1)
return calculatePostfix(infix2ToPostfix(formulaExpression))
}
// (12.3+0.1)*2.0+2
// 12.30.1+2.0*2+
// 后缀式计算
func calculatePostfix(postfix []string) float64 {
stack := Stack{}
fixLen := len(postfix)
for i := 0; i < fixLen; i++ {
nextChar := postfix[i]
// 数字:直接压栈
if _, err := strconv.ParseFloat(nextChar, 64); err == nil {
stack.Push(nextChar)
} else {
switch nextChar {
case "√":
// 操作符:取出数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", math.Sqrt(num1)))
case "²":
// 操作符:取出数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", math.Pow(num1, 2)))
case "+":
// 操作符:取出两个数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
num2, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", num2+num1))
case "-":
// 操作符:取出两个数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
num2, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", num2-num1))
case "*":
// 操作符:取出两个数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
num2, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", num2*num1))
case "/":
// 操作符:取出两个数字计算值,再将结果压栈
num1, _ := strconv.ParseFloat(stack.Pop(), 64)
num2, _ := strconv.ParseFloat(stack.Pop(), 64)
stack.Push(fmt.Sprintf("%v", num2/num1))
}
}
}
result, _ := strconv.ParseFloat(stack.Top(), 64)
return result
}
// 中缀表达式转后缀表达式
func infix2ToPostfix(expStr string) []string {
stack := Stack{}
postfix := make([]string, 0)
exp := []rune(expStr)
expLen := len(exp)
// 遍历整个表达式
for i := 0; i < expLen; i++ {
char := string(exp[i])
switch char {
case " ":
continue
case "(":
// 左括号直接入栈
stack.Push("(")
case ")":
// 右括号则弹出元素直到遇到左括号
for !stack.IsEmpty() {
preChar := stack.Top()
if preChar == "(" {
stack.Pop() // 弹出 "("
break
}
postfix = append(postfix, preChar)
stack.Pop()
}
// 数字则直接输出
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".":
j := i
digit := ""
for ; j < expLen && (unicode.IsDigit(rune(exp[j])) || "." == string(exp[j])); j++ {
digit += string(exp[j])
}
postfix = append(postfix, digit)
i = j - 1 // i 向前跨越一个整数,由于执行了一步多余的 j++,需要减 1
default:
// 操作符:遇到高优先级的运算符,不断弹出,直到遇见更低优先级运算符
for !stack.IsEmpty() {
top := stack.Top()
if top == "(" || isLower(top, char) {
break
}
postfix = append(postfix, top)
stack.Pop()
}
// 低优先级的运算符入栈
stack.Push(char)
}
}
// 栈不空则全部输出
for !stack.IsEmpty() {
postfix = append(postfix, stack.Pop())
}
return postfix
}
// 比较运算符栈栈顶 top 和新运算符 newTop 的优先级高低
func isLower(top string, newTop string) bool {
// 注意 a + b + c 的后缀表达式是 ab + c +,不是 abc + +
//优先级定义
operatorPriority := map[string]uint16{
"+": 0,
"-": 0,
"*": 1,
"/": 1,
"√": 3,
"²": 3,
"(": 5,
}
Priority := operatorPriority[newTop] > operatorPriority[top]
return Priority
//switch top {
//case "+", "-":
// if newTop == "*" || newTop == "/" {
// return true
// }
//case "(":
// return true
//}
//return false
}
type Stack struct {
data [1024]string
top int
}
func (s *Stack) Push(d string) {
s.data[s.top] = d
s.top++
}
func (s *Stack) Pop() (d string) {
if s.top == 0 {
//err = fmt.Errorf("stack is empty")
}
s.top--
d = s.data[s.top]
return
}
func (s *Stack) Top() (d string) {
if s.top == 0 {
//err = fmt.Errorf("stack is empty")
}
d = s.data[s.top-1]
return
}
func (s *Stack) IsEmpty() bool {
return s.top == 0
}