package calculator import ( "errors" "math" ) const ( RadianMode = iota AngleMode ) type defS struct { argc int fun func(expr ...ExprAST) float64 } // enum "RadianMode", "AngleMode" var TrigonometricMode = RadianMode var defConst = map[string]float64{ "pi": math.Pi, } var defFunc map[string]defS func init() { defFunc = map[string]defS{ "sin": {1, defSin}, "cos": {1, defCos}, "tan": {1, defTan}, "cot": {1, defCot}, "sec": {1, defSec}, "csc": {1, defCsc}, "abs": {1, defAbs}, "ceil": {1, defCeil}, "floor": {1, defFloor}, "round": {1, defRound}, "sqrt": {1, defSqrt}, "cbrt": {1, defCbrt}, "noerr": {1, defNoerr}, "max": {-1, defMax}, "min": {-1, defMin}, } } // sin(pi/2) = 1 func defSin(expr ...ExprAST) float64 { return math.Sin(expr2Radian(expr[0])) } // cos(0) = 1 func defCos(expr ...ExprAST) float64 { return math.Cos(expr2Radian(expr[0])) } // tan(pi/4) = 1 func defTan(expr ...ExprAST) float64 { return math.Tan(expr2Radian(expr[0])) } // cot(pi/4) = 1 func defCot(expr ...ExprAST) float64 { return 1 / defTan(expr...) } // sec(0) = 1 func defSec(expr ...ExprAST) float64 { return 1 / defCos(expr...) } // csc(pi/2) = 1 func defCsc(expr ...ExprAST) float64 { return 1 / defSin(expr...) } // abs(-2) = 2 func defAbs(expr ...ExprAST) float64 { return math.Abs(ExprASTResult(expr[0])) } // ceil(4.2) = ceil(4.8) = 5 func defCeil(expr ...ExprAST) float64 { return math.Ceil(ExprASTResult(expr[0])) } // floor(4.2) = floor(4.8) = 4 func defFloor(expr ...ExprAST) float64 { return math.Floor(ExprASTResult(expr[0])) } // round(4.2) = 4 // round(4.6) = 5 func defRound(expr ...ExprAST) float64 { return math.Round(ExprASTResult(expr[0])) } // sqrt(4) = 2 // sqrt(4) = abs(sqrt(4)) // returns only the absolute value of the result func defSqrt(expr ...ExprAST) float64 { return math.Sqrt(ExprASTResult(expr[0])) } // cbrt(27) = 3 func defCbrt(expr ...ExprAST) float64 { return math.Cbrt(ExprASTResult(expr[0])) } // max(2) = 2 // max(2, 3) = 3 // max(2, 3, 1) = 3 func defMax(expr ...ExprAST) float64 { if len(expr) == 0 { panic(errors.New("calling function `max` must have at least one parameter.")) } if len(expr) == 1 { return ExprASTResult(expr[0]) } maxV := ExprASTResult(expr[0]) for i := 1; i < len(expr); i++ { v := ExprASTResult(expr[i]) maxV = math.Max(maxV, v) } return maxV } // min(2) = 2 // min(2, 3) = 2 // min(2, 3, 1) = 1 func defMin(expr ...ExprAST) float64 { if len(expr) == 0 { panic(errors.New("calling function `min` must have at least one parameter.")) } if len(expr) == 1 { return ExprASTResult(expr[0]) } maxV := ExprASTResult(expr[0]) for i := 1; i < len(expr); i++ { v := ExprASTResult(expr[i]) maxV = math.Min(maxV, v) } return maxV } // noerr(1/0) = 0 // noerr(2.5/(1-1)) = 0 func defNoerr(expr ...ExprAST) (r float64) { defer func() { if e := recover(); e != nil { r = 0 } }() return ExprASTResult(expr[0]) }