diff --git a/calc.go b/calc.go index c2fc15c..c277212 100644 --- a/calc.go +++ b/calc.go @@ -425,6 +425,7 @@ type formulaFuncs struct { // FACTDOUBLE // FALSE // F.DIST +// F.DIST.RT // FDIST // FIND // FINDB @@ -609,6 +610,7 @@ type formulaFuncs struct { // SEC // SECH // SECOND +// SERIESSUM // SHEET // SHEETS // SIGN @@ -4655,6 +4657,40 @@ func (fn *formulaFuncs) SECH(argsList *list.List) formulaArg { return newNumberFormulaArg(1 / math.Cosh(number.Number)) } +// SERIESSUM function returns the sum of a power series. The syntax of the +// function is: +// +// SERIESSUM(x,n,m,coefficients) +// +func (fn *formulaFuncs) SERIESSUM(argsList *list.List) formulaArg { + if argsList.Len() != 4 { + return newErrorFormulaArg(formulaErrorVALUE, "SERIESSUM requires 4 arguments") + } + var x, n, m formulaArg + if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber { + return x + } + if n = argsList.Front().Next().Value.(formulaArg).ToNumber(); n.Type != ArgNumber { + return n + } + if m = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); m.Type != ArgNumber { + return m + } + var result, i float64 + for _, coefficient := range argsList.Back().Value.(formulaArg).ToList() { + if coefficient.Value() == "" { + continue + } + num := coefficient.ToNumber() + if num.Type != ArgNumber { + return num + } + result += num.Number * math.Pow(x.Number, (n.Number+(m.Number*float64(i)))) + i++ + } + return newNumberFormulaArg(result) +} + // SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied // number. I.e. if the number is positive, the Sign function returns +1, if // the number is negative, the function returns -1 and if the number is 0 @@ -7137,6 +7173,19 @@ func (fn *formulaFuncs) FDIST(argsList *list.List) formulaArg { return newNumberFormulaArg(1 - fn.BETADIST(args).Number) } +// FdotDISTdotRT function calculates the (right-tailed) F Probability +// Distribution, which measures the degree of diversity between two data sets. +// The syntax of the function is: +// +// F.DIST.RT(x,deg_freedom1,deg_freedom2) +// +func (fn *formulaFuncs) FdotDISTdotRT(argsList *list.List) formulaArg { + if argsList.Len() != 3 { + return newErrorFormulaArg(formulaErrorVALUE, "F.DIST.RT requires 3 arguments") + } + return fn.FDIST(argsList) +} + // prepareFinvArgs checking and prepare arguments for the formula function // F.INV, F.INV.RT and FINV. func (fn *formulaFuncs) prepareFinvArgs(name string, argsList *list.List) formulaArg { @@ -11431,7 +11480,7 @@ func lookupBinarySearch(vertical bool, lookupValue, lookupArray, matchMode, sear } else { tableArray = lookupArray.Matrix[0] } - var low, high, lastMatchIdx = 0, len(tableArray) - 1, -1 + low, high, lastMatchIdx := 0, len(tableArray)-1, -1 count := high for low <= high { mid := low + (high-low)/2 diff --git a/calc_test.go b/calc_test.go index 1b59e78..f9da26d 100644 --- a/calc_test.go +++ b/calc_test.go @@ -668,6 +668,9 @@ func TestCalcCellValue(t *testing.T) { "=_xlfn.SECH(-3.14159265358979)": "0.0862667383340547", "=_xlfn.SECH(0)": "1", "=_xlfn.SECH(_xlfn.SECH(0))": "0.648054273663885", + // SERIESSUM + "=SERIESSUM(1,2,3,A1:A4)": "6", + "=SERIESSUM(1,2,3,A1:B5)": "15", // SIGN "=SIGN(9.5)": "1", "=SIGN(-9.5)": "-1", @@ -940,6 +943,8 @@ func TestCalcCellValue(t *testing.T) { // F.DIST "=F.DIST(1,2,5,TRUE)": "0.568798849628308", "=F.DIST(1,2,5,FALSE)": "0.308000821694066", + // F.DIST.RT + "=F.DIST.RT(5,1,2)": "0.154845745271483", // F.INV "=F.INV(0.9,2,5)": "3.77971607877395", // FINV @@ -2315,6 +2320,12 @@ func TestCalcCellValue(t *testing.T) { // _xlfn.SECH "=_xlfn.SECH()": "SECH requires 1 numeric argument", `=_xlfn.SECH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", + // SERIESSUM + "=SERIESSUM()": "SERIESSUM requires 4 arguments", + "=SERIESSUM(\"\",2,3,A1:A4)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=SERIESSUM(1,\"\",3,A1:A4)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=SERIESSUM(1,2,\"\",A1:A4)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=SERIESSUM(1,2,3,A1:D1)": "strconv.ParseFloat: parsing \"Month\": invalid syntax", // SIGN "=SIGN()": "SIGN requires 1 numeric argument", `=SIGN("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", @@ -2657,6 +2668,16 @@ func TestCalcCellValue(t *testing.T) { "=F.DIST(5,10000000000,2,TRUE)": "#NUM!", "=F.DIST(5,1,0,TRUE)": "#NUM!", "=F.DIST(5,1,10000000000,TRUE)": "#NUM!", + // F.DIST.RT + "=F.DIST.RT()": "F.DIST.RT requires 3 arguments", + "=F.DIST.RT(\"\",1,2)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=F.DIST.RT(5,\"\",2)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=F.DIST.RT(5,1,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=F.DIST.RT(-1,1,2)": "#NUM!", + "=F.DIST.RT(5,0,2)": "#NUM!", + "=F.DIST.RT(5,10000000000,2)": "#NUM!", + "=F.DIST.RT(5,1,0)": "#NUM!", + "=F.DIST.RT(5,1,10000000000)": "#NUM!", // F.INV "=F.INV()": "F.INV requires 3 arguments", "=F.INV(\"\",1,2)": "strconv.ParseFloat: parsing \"\": invalid syntax",