summaryrefslogtreecommitdiff
path: root/calc.go
diff options
context:
space:
mode:
Diffstat (limited to 'calc.go')
-rw-r--r--calc.go101
1 files changed, 100 insertions, 1 deletions
diff --git a/calc.go b/calc.go
index 7c912eb..568f044 100644
--- a/calc.go
+++ b/calc.go
@@ -220,7 +220,9 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
argsList.PushBack(opfdStack.Pop())
}
// call formula function to evaluate
- result, err := callFuncByName(&formulaFuncs{}, strings.ReplaceAll(opfStack.Peek().(efp.Token).TValue, "_xlfn.", ""), []reflect.Value{reflect.ValueOf(argsList)})
+ result, err := callFuncByName(&formulaFuncs{}, strings.NewReplacer(
+ "_xlfn", "", ".", "").Replace(opfStack.Peek().(efp.Token).TValue),
+ []reflect.Value{reflect.ValueOf(argsList)})
if err != nil {
return efp.Token{}, err
}
@@ -801,6 +803,103 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) {
return
}
+// CEILING function rounds a supplied number away from zero, to the nearest
+// multiple of a given number. The syntax of the function is:
+//
+// CEILING(number,significance)
+//
+func (fn *formulaFuncs) CEILING(argsList *list.List) (result string, err error) {
+ if argsList.Len() == 0 {
+ err = errors.New("CEILING requires at least 1 argument")
+ return
+ }
+ if argsList.Len() > 2 {
+ err = errors.New("CEILING allows at most 2 arguments")
+ return
+ }
+ var number, significance float64
+ number, err = strconv.ParseFloat(argsList.Front().Value.(efp.Token).TValue, 64)
+ if err != nil {
+ return
+ }
+ significance = 1
+ if number < 0 {
+ significance = -1
+ }
+ if argsList.Len() > 1 {
+ significance, err = strconv.ParseFloat(argsList.Back().Value.(efp.Token).TValue, 64)
+ if err != nil {
+ return
+ }
+ }
+ if significance < 0 && number > 0 {
+ err = errors.New("negative sig to CEILING invalid")
+ return
+ }
+ if argsList.Len() == 1 {
+ result = fmt.Sprintf("%g", math.Ceil(number))
+ return
+ }
+ number, res := math.Modf(number / significance)
+ if res > 0 {
+ number++
+ }
+ result = fmt.Sprintf("%g", number*significance)
+ return
+}
+
+// CEILINGMATH function rounds a supplied number up to a supplied multiple of
+// significance. The syntax of the function is:
+//
+// CEILING.MATH(number,[significance],[mode])
+//
+func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err error) {
+ if argsList.Len() == 0 {
+ err = errors.New("CEILING.MATH requires at least 1 argument")
+ return
+ }
+ if argsList.Len() > 3 {
+ err = errors.New("CEILING.MATH allows at most 3 arguments")
+ return
+ }
+ var number, significance, mode float64 = 0, 1, 1
+ number, err = strconv.ParseFloat(argsList.Front().Value.(efp.Token).TValue, 64)
+ if err != nil {
+ return
+ }
+ if number < 0 {
+ significance = -1
+ }
+ if argsList.Len() > 1 {
+ significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(efp.Token).TValue, 64)
+ if err != nil {
+ return
+ }
+ }
+ if argsList.Len() == 1 {
+ result = fmt.Sprintf("%g", math.Ceil(number))
+ return
+ }
+ if argsList.Len() > 2 {
+ mode, err = strconv.ParseFloat(argsList.Back().Value.(efp.Token).TValue, 64)
+ if err != nil {
+ return
+ }
+ }
+ val, res := math.Modf(number / significance)
+ _, _ = res, mode
+ if res != 0 {
+ if number > 0 {
+ val++
+ } else if mode < 0 {
+ val--
+ }
+ }
+
+ result = fmt.Sprintf("%g", val*significance)
+ return
+}
+
// GCD function returns the greatest common divisor of two or more supplied
// integers. The syntax of the function is:
//