diff --git a/calc.go b/calc.go index 57b2cda..0931012 100644 --- a/calc.go +++ b/calc.go @@ -393,6 +393,7 @@ type formulaFuncs struct { // COUPPCD // COVAR // COVARIANCE.P +// COVARIANCE.S // CRITBINOM // CSC // CSCH @@ -645,6 +646,7 @@ type formulaFuncs struct { // STDEV.S // STDEVA // STDEVP +// STDEVPA // SUBSTITUTE // SUM // SUMIF @@ -6851,14 +6853,11 @@ func (fn *formulaFuncs) CONFIDENCEdotT(argsList *list.List) formulaArg { }, size.Number/2, size.Number) / math.Sqrt(size.Number)) } -// COVAR function calculates the covariance of two supplied sets of values. The -// syntax of the function is: -// -// COVAR(array1,array2) -// -func (fn *formulaFuncs) COVAR(argsList *list.List) formulaArg { +// covar is an implementation of the formula functions COVAR, COVARIANCE.P and +// COVARIANCE.S. +func (fn *formulaFuncs) covar(name string, argsList *list.List) formulaArg { if argsList.Len() != 2 { - return newErrorFormulaArg(formulaErrorVALUE, "COVAR requires 2 arguments") + return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name)) } array1 := argsList.Front().Value.(formulaArg) array2 := argsList.Back().Value.(formulaArg) @@ -6881,19 +6880,37 @@ func (fn *formulaFuncs) COVAR(argsList *list.List) formulaArg { } result += (arg1.Number - mean1.Number) * (arg2.Number - mean2.Number) } + if name == "COVARIANCE.S" { + return newNumberFormulaArg(result / float64(n-skip-1)) + } return newNumberFormulaArg(result / float64(n-skip)) } +// COVAR function calculates the covariance of two supplied sets of values. The +// syntax of the function is: +// +// COVAR(array1,array2) +// +func (fn *formulaFuncs) COVAR(argsList *list.List) formulaArg { + return fn.covar("COVAR", argsList) +} + // COVARIANCEdotP function calculates the population covariance of two supplied // sets of values. The syntax of the function is: // // COVARIANCE.P(array1,array2) // func (fn *formulaFuncs) COVARIANCEdotP(argsList *list.List) formulaArg { - if argsList.Len() != 2 { - return newErrorFormulaArg(formulaErrorVALUE, "COVARIANCE.P requires 2 arguments") - } - return fn.COVAR(argsList) + return fn.covar("COVARIANCE.P", argsList) +} + +// COVARIANCEdotS function calculates the sample covariance of two supplied +// sets of values. The syntax of the function is: +// +// COVARIANCE.S(array1,array2) +// +func (fn *formulaFuncs) COVARIANCEdotS(argsList *list.List) formulaArg { + return fn.covar("COVARIANCE.S", argsList) } // calcStringCountSum is part of the implementation countSum. @@ -9131,12 +9148,17 @@ func (fn *formulaFuncs) STANDARDIZE(argsList *list.List) formulaArg { return newNumberFormulaArg((x.Number - mean.Number) / stdDev.Number) } -// stdevp is an implementation of the formula functions STDEVP and STDEV.P. +// stdevp is an implementation of the formula functions STDEVP, STDEV.P and +// STDEVPA. func (fn *formulaFuncs) stdevp(name string, argsList *list.List) formulaArg { if argsList.Len() < 1 { return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name)) } - varp := fn.VARP(argsList) + fnName := "VARP" + if name == "STDEVPA" { + fnName = "VARPA" + } + varp := fn.vars(fnName, argsList) if varp.Type != ArgNumber { return varp } @@ -9161,6 +9183,15 @@ func (fn *formulaFuncs) STDEVdotP(argsList *list.List) formulaArg { return fn.stdevp("STDEV.P", argsList) } +// STDEVPA function calculates the standard deviation of a supplied set of +// values. The syntax of the function is: +// +// STDEVPA(number1,[number2],...) +// +func (fn *formulaFuncs) STDEVPA(argsList *list.List) formulaArg { + return fn.stdevp("STDEVPA", argsList) +} + // getTDist is an implementation for the beta distribution probability density // function. func getTDist(T, fDF, nType float64) float64 { @@ -9576,6 +9607,9 @@ func (fn *formulaFuncs) vars(name string, argsList *list.List) formulaArg { } for arg := argsList.Front(); arg != nil; arg = arg.Next() { for _, token := range arg.Value.(formulaArg).ToList() { + if token.Value() == "" { + continue + } num := token.ToNumber() if token.Value() != "TRUE" && num.Type == ArgNumber { summerA += num.Number * num.Number diff --git a/calc_test.go b/calc_test.go index c553d12..98d3d45 100644 --- a/calc_test.go +++ b/calc_test.go @@ -1162,6 +1162,10 @@ func TestCalcCellValue(t *testing.T) { "=STDEVP(A1:B2,6,-1)": "2.40947204913349", // STDEV.P "=STDEV.P(A1:B2,6,-1)": "2.40947204913349", + // STDEVPA + "=STDEVPA(1,3,5,2)": "1.4790199457749", + "=STDEVPA(1,3,5,2,1,0)": "1.63299316185545", + "=STDEVPA(1,3,5,2,TRUE,\"text\")": "1.63299316185545", // T.DIST "=T.DIST(1,10,TRUE)": "0.82955343384897", "=T.DIST(-1,10,TRUE)": "0.17044656615103", @@ -1190,8 +1194,8 @@ func TestCalcCellValue(t *testing.T) { "=VAR(1,3,5,0,C1)": "4.91666666666667", "=VAR(1,3,5,0,C1,TRUE)": "4", // VARA - "=VARA(1,3,5,0,C1)": "4.7", - "=VARA(1,3,5,0,C1,TRUE)": "3.86666666666667", + "=VARA(1,3,5,0,C1)": "4.91666666666667", + "=VARA(1,3,5,0,C1,TRUE)": "4", // VARP "=VARP(A1:A5)": "1.25", "=VARP(1,3,5,0,C1,TRUE)": "3.2", @@ -1201,8 +1205,8 @@ func TestCalcCellValue(t *testing.T) { "=VAR.S(1,3,5,0,C1)": "4.91666666666667", "=VAR.S(1,3,5,0,C1,TRUE)": "4", // VARPA - "=VARPA(1,3,5,0,C1)": "3.76", - "=VARPA(1,3,5,0,C1,TRUE)": "3.22222222222222", + "=VARPA(1,3,5,0,C1)": "3.6875", + "=VARPA(1,3,5,0,C1,TRUE)": "3.2", // WEIBULL "=WEIBULL(1,3,1,FALSE)": "1.10363832351433", "=WEIBULL(2,5,1.5,TRUE)": "0.985212776817482", @@ -3050,6 +3054,9 @@ func TestCalcCellValue(t *testing.T) { // STDEV.P "=STDEV.P()": "STDEV.P requires at least 1 argument", "=STDEV.P(\"\")": "#DIV/0!", + // STDEVPA + "=STDEVPA()": "STDEVPA requires at least 1 argument", + "=STDEVPA(\"\")": "#DIV/0!", // T.DIST "=T.DIST()": "T.DIST requires 3 arguments", "=T.DIST(\"\",10,TRUE)": "strconv.ParseFloat: parsing \"\": invalid syntax", @@ -4361,6 +4368,8 @@ func TestCalcCOVAR(t *testing.T) { "=COVAR(A2:A9,B2:B9)": "16.633125", "=COVARIANCE.P(A1:A9,B1:B9)": "16.633125", "=COVARIANCE.P(A2:A9,B2:B9)": "16.633125", + "=COVARIANCE.S(A1:A9,B1:B9)": "19.0092857142857", + "=COVARIANCE.S(A2:A9,B2:B9)": "19.0092857142857", } for formula, expected := range formulaList { assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula)) @@ -4373,6 +4382,8 @@ func TestCalcCOVAR(t *testing.T) { "=COVAR(A2:A9,B3:B3)": "#N/A", "=COVARIANCE.P()": "COVARIANCE.P requires 2 arguments", "=COVARIANCE.P(A2:A9,B3:B3)": "#N/A", + "=COVARIANCE.S()": "COVARIANCE.S requires 2 arguments", + "=COVARIANCE.S(A2:A9,B3:B3)": "#N/A", } for formula, expected := range calcError { assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))