package staros import ( "errors" "fmt" "math" "strconv" "strings" ) func Calc(math string) (float64, error) { math = strings.Replace(math, " ", "", -1) math = strings.ToLower(math) if err := check(math); err != nil { return 0, err } result,err:=calc(math) if err!=nil { return 0,err } return floatRound(result,15),nil } func floatRound(f float64, n int) float64 { format := "%." + strconv.Itoa(n) + "f" res, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64) return res } func check(math string) error { math = strings.Replace(math, " ", "", -1) math = strings.ToLower(math) var bracketSum int var signReady bool for k, v := range math { if string([]rune{v}) == "(" { bracketSum++ } if string([]rune{v}) == ")" { bracketSum-- } if bracketSum < 0 { return fmt.Errorf("err at position %d.Reason is right bracket position not correct,except (", k) } if containSign(string([]rune{v})) { if signReady { if string([]rune{v}) != "+" && string([]rune{v}) != "-" { return fmt.Errorf("err at position %d.Reason is sign %s not correct", k, string([]rune{v})) } } else { signReady = true continue } } signReady = false } if bracketSum != 0 { return fmt.Errorf("Error:right bracket is not equal as left bracket") } return nil } func calc(math string) (float64, error) { var bracketLeft int var bracketRight int var DupStart int = -1 for pos, str := range math { if string(str) == "(" { bracketLeft = pos } if string(str) == ")" { bracketRight = pos break } } if bracketRight == 0 && bracketLeft != 0 || (bracketLeft > bracketRight) { return 0, fmt.Errorf("Error:bracket not correct at %d ,except )", bracketLeft) } if bracketRight == 0 && bracketLeft == 0 { return calcLong(math) } line := math[bracketLeft+1 : bracketRight] num, err := calcLong(line) if err != nil { return 0, err } for i := bracketLeft - 1; i >= 0; i-- { if !containSign(math[i : i+1]) { DupStart = i continue } break } if DupStart != -1 { sign := math[DupStart:bracketLeft] num, err := calcDuaFloat(sign, num) if err != nil { return 0, err } math = math[:DupStart] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:] DupStart = -1 } else { math = math[:bracketLeft] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:] } return calc(math) } func calcLong(str string) (float64, error) { var sigReady bool = false var sigApply bool = false var numPool []float64 var operPool []string var numStr string var oper string if str[0:1] == "+" || str[0:1] == "-" { sigReady = true } for _, stp := range str { if sigReady && containSign(string(stp)) { sigReady = false sigApply = true oper = string(stp) continue } if !containSign(string(stp)) { sigReady = false numStr = string(append([]rune(numStr), stp)) continue } if !sigReady { sigReady = true } if sigApply { num, err := calcDua(oper, numStr) if err != nil { return 0, err } sigApply = false numPool = append(numPool, num) } else { num, err := parseNumbic(numStr) if err != nil { return 0, err } numPool = append(numPool, num) } numStr = "" operPool = append(operPool, string(stp)) } if sigApply { num, err := calcDua(oper, numStr) if err != nil { return 0, err } numPool = append(numPool, num) } else { num, err := parseNumbic(numStr) if err != nil { return 0, err } numPool = append(numPool, num) } return calcPool(numPool, operPool) } func calcPool(numPool []float64, operPool []string) (float64, error) { if len(numPool) == 1 && len(operPool) == 0 { return numPool[0], nil } if len(numPool) < len(operPool) { return 0, errors.New(("Operate Signal Is too much")) } calcFunc := func(k int, v string) (float64, error) { num, err := calcSigFloat(numPool[k], v, numPool[k+1]) if err != nil { return 0, err } tmp := append(numPool[:k], num) numPool = append(tmp, numPool[k+2:]...) operPool = append(operPool[:k], operPool[k+1:]...) return calcPool(numPool, operPool) } for k, v := range operPool { if v == "^" { return calcFunc(k, v) } } for k, v := range operPool { if v == "*" || v == "/" { return calcFunc(k, v) } } for k, v := range operPool { return calcFunc(k, v) } return 0, nil } func calcSigFloat(floatA float64, b string, floatC float64) (float64, error) { switch b { case "+": return floatRound(floatA + floatC,15), nil case "-": return floatRound(floatA - floatC,15), nil case "*": return floatRound(floatA * floatC,15), nil case "/": if floatC == 0 { return 0, errors.New("Divisor cannot be 0") } return floatRound(floatA / floatC,15), nil case "^": return math.Pow(floatA, floatC), nil } return 0, fmt.Errorf("unexpect method:%s", b) } func calcSig(a, b, c string) (float64, error) { floatA, err := parseNumbic(a) if err != nil { return 0, err } floatC, err := parseNumbic(c) if err != nil { return 0, err } return calcSigFloat(floatA, b, floatC) } func calcDuaFloat(a string, floatB float64) (float64, error) { switch a { case "sin": return math.Sin(floatB), nil case "cos": return math.Cos(floatB), nil case "tan": return math.Tan(floatB), nil case "abs": return math.Abs(floatB), nil case "arcsin": return math.Asin(floatB), nil case "arccos": return math.Acos(floatB), nil case "arctan": return math.Atan(floatB), nil case "sqrt": return math.Sqrt(floatB), nil case "loge": return math.Log(floatB), nil case "log10": return math.Log10(floatB), nil case "log2": return math.Log2(floatB), nil case "floor": return math.Floor(floatB), nil case "ceil": return math.Ceil(floatB), nil case "round": return math.Round(floatB), nil case "trunc": return math.Trunc(floatB), nil case "+": return 0 + floatB, nil case "-": return 0 - floatB, nil } return 0, fmt.Errorf("unexpect method:%s", a) } func calcDua(a, b string) (float64, error) { floatB, err := parseNumbic(b) if err != nil { return 0, err } return calcDuaFloat(a, floatB) } func parseNumbic(str string) (float64, error) { switch str { case "pi": return float64(math.Pi), nil case "e": return float64(math.E), nil default: return strconv.ParseFloat(str, 64) } } func containSign(str string) bool { var sign []string = []string{"+", "-", "*", "/", "^"} for _, v := range sign { if str == v { return true } } return false } func contain(pool []string, str string) bool { for _, v := range pool { if v == str { return true } } return false }