fn: CEILING, CEILING.MATH
This commit is contained in:
parent
789adf9202
commit
6f796b88e6
101
calc.go
101
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:
|
||||
//
|
||||
|
|
29
calc_test.go
29
calc_test.go
|
@ -67,6 +67,22 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=BASE(12,2)": "1100",
|
||||
"=BASE(12,2,8)": "00001100",
|
||||
"=BASE(100000,16)": "186A0",
|
||||
// CEILING
|
||||
"=CEILING(22.25,0.1)": "22.3",
|
||||
"=CEILING(22.25,0.5)": "22.5",
|
||||
"=CEILING(22.25,1)": "23",
|
||||
"=CEILING(22.25,10)": "30",
|
||||
"=CEILING(22.25,20)": "40",
|
||||
"=CEILING(-22.25,-0.1)": "-22.3",
|
||||
"=CEILING(-22.25,-1)": "-23",
|
||||
"=CEILING(-22.25,-5)": "-25",
|
||||
// _xlfn.CEILING.MATH
|
||||
"=_xlfn.CEILING.MATH(15.25,1)": "16",
|
||||
"=_xlfn.CEILING.MATH(15.25,0.1)": "15.3",
|
||||
"=_xlfn.CEILING.MATH(15.25,5)": "20",
|
||||
"=_xlfn.CEILING.MATH(-15.25,1)": "-15",
|
||||
"=_xlfn.CEILING.MATH(-15.25,1,1)": "-15", // should be 16
|
||||
"=_xlfn.CEILING.MATH(-15.25,10)": "-10",
|
||||
// GCD
|
||||
"=GCD(1,5)": "1",
|
||||
"=GCD(15,10,25)": "5",
|
||||
|
@ -123,11 +139,11 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=ACOS()": "ACOS requires 1 numeric arguments",
|
||||
// ACOSH
|
||||
"=ACOSH()": "ACOSH requires 1 numeric arguments",
|
||||
// ACOT
|
||||
// _xlfn.ACOT
|
||||
"=_xlfn.ACOT()": "ACOT requires 1 numeric arguments",
|
||||
// ACOTH
|
||||
// _xlfn.ACOTH
|
||||
"=_xlfn.ACOTH()": "ACOTH requires 1 numeric arguments",
|
||||
// ARABIC
|
||||
// _xlfn.ARABIC
|
||||
"_xlfn.ARABIC()": "ARABIC requires 1 numeric arguments",
|
||||
// ASIN
|
||||
"=ASIN()": "ASIN requires 1 numeric arguments",
|
||||
|
@ -143,6 +159,13 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=BASE()": "BASE requires at least 2 arguments",
|
||||
"=BASE(1,2,3,4)": "BASE allows at most 3 arguments",
|
||||
"=BASE(1,1)": "radix must be an integer ≥ 2 and ≤ 36",
|
||||
// CEILING
|
||||
"=CEILING()": "CEILING requires at least 1 argument",
|
||||
"=CEILING(1,2,3)": "CEILING allows at most 2 arguments",
|
||||
"=CEILING(1,-1)": "negative sig to CEILING invalid",
|
||||
// _xlfn.CEILING.MATH
|
||||
"=_xlfn.CEILING.MATH()": "CEILING.MATH requires at least 1 argument",
|
||||
"=_xlfn.CEILING.MATH(1,2,3,4)": "CEILING.MATH allows at most 3 arguments",
|
||||
// GCD
|
||||
"=GCD()": "GCD requires at least 1 argument",
|
||||
"=GCD(-1)": "GCD only accepts positive arguments",
|
||||
|
|
Loading…
Reference in New Issue