Prechádzať zdrojové kódy

#65, new fn: POISSON.DIST, POISSON, SKEW, and STDEV.S

xuri 4 rokov pred
rodič
commit
3903c106a4
2 zmenil súbory, kde vykonal 126 pridanie a 0 odobranie
  1. 100 0
      calc.go
  2. 26 0
      calc_test.go

+ 100 - 0
calc.go

@@ -341,6 +341,8 @@ var tokenPriority = map[string]int{
 //    OR
 //    PERMUT
 //    PI
+//    POISSON.DIST
+//    POISSON
 //    POWER
 //    PRODUCT
 //    PROPER
@@ -365,10 +367,12 @@ var tokenPriority = map[string]int{
 //    SIGN
 //    SIN
 //    SINH
+//    SKEW
 //    SMALL
 //    SQRT
 //    SQRTPI
 //    STDEV
+//    STDEV.S
 //    STDEVA
 //    SUBSTITUTE
 //    SUM
@@ -3396,6 +3400,18 @@ func (fn *formulaFuncs) STDEV(argsList *list.List) formulaArg {
 	return fn.stdev(false, argsList)
 }
 
+// STDEVdotS function calculates the sample standard deviation of a supplied
+// set of values. The syntax of the function is:
+//
+//    STDEV.S(number1,[number2],...)
+//
+func (fn *formulaFuncs) STDEVdotS(argsList *list.List) formulaArg {
+	if argsList.Len() < 1 {
+		return newErrorFormulaArg(formulaErrorVALUE, "STDEV.S requires at least 1 argument")
+	}
+	return fn.stdev(false, argsList)
+}
+
 // STDEVA function estimates standard deviation based on a sample. The
 // standard deviation is a measure of how widely values are dispersed from
 // the average value (the mean). The syntax of the function is:
@@ -3472,6 +3488,53 @@ func (fn *formulaFuncs) stdev(stdeva bool, argsList *list.List) formulaArg {
 	return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 }
 
+// POISSONdotDIST function calculates the Poisson Probability Mass Function or
+// the Cumulative Poisson Probability Function for a supplied set of
+// parameters. The syntax of the function is:
+//
+//    POISSON.DIST(x,mean,cumulative)
+//
+func (fn *formulaFuncs) POISSONdotDIST(argsList *list.List) formulaArg {
+	if argsList.Len() != 3 {
+		return newErrorFormulaArg(formulaErrorVALUE, "POISSON.DIST requires 3 arguments")
+	}
+	return fn.POISSON(argsList)
+}
+
+// POISSON function calculates the Poisson Probability Mass Function or the
+// Cumulative Poisson Probability Function for a supplied set of parameters.
+// The syntax of the function is:
+//
+//    POISSON(x,mean,cumulative)
+//
+func (fn *formulaFuncs) POISSON(argsList *list.List) formulaArg {
+	if argsList.Len() != 3 {
+		return newErrorFormulaArg(formulaErrorVALUE, "POISSON requires 3 arguments")
+	}
+	var x, mean, cumulative formulaArg
+	if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
+		return x
+	}
+	if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
+		return mean
+	}
+	if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
+		return cumulative
+	}
+	if x.Number < 0 || mean.Number <= 0 {
+		return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
+	}
+	if cumulative.Number == 1 {
+		summer := 0.0
+		floor := math.Floor(x.Number)
+		for i := 0; i <= int(floor); i++ {
+			summer += math.Pow(mean.Number, float64(i)) / fact(float64(i))
+		}
+		return newNumberFormulaArg(math.Exp(0-mean.Number) * summer)
+	}
+	return newNumberFormulaArg(math.Exp(0-mean.Number) * math.Pow(mean.Number, x.Number) / fact(x.Number))
+}
+
 // SUM function adds together a supplied set of numbers and returns the sum of
 // these values. The syntax of the function is:
 //
@@ -4479,6 +4542,43 @@ func (fn *formulaFuncs) PERMUT(argsList *list.List) formulaArg {
 	return newNumberFormulaArg(math.Round(fact(number.Number) / fact(number.Number-chosen.Number)))
 }
 
+// SKEW function calculates the skewness of the distribution of a supplied set
+// of values. The syntax of the function is:
+//
+//    SKEW(number1,[number2],...)
+//
+func (fn *formulaFuncs) SKEW(argsList *list.List) formulaArg {
+	if argsList.Len() < 1 {
+		return newErrorFormulaArg(formulaErrorVALUE, "SKEW requires at least 1 argument")
+	}
+	mean, stdDev, count, summer := fn.AVERAGE(argsList), fn.STDEV(argsList), 0.0, 0.0
+	for arg := argsList.Front(); arg != nil; arg = arg.Next() {
+		token := arg.Value.(formulaArg)
+		switch token.Type {
+		case ArgNumber, ArgString:
+			num := token.ToNumber()
+			if num.Type == ArgError {
+				return num
+			}
+			summer += math.Pow((num.Number-mean.Number)/stdDev.Number, 3)
+			count++
+		case ArgList, ArgMatrix:
+			for _, row := range token.ToList() {
+				numArg := row.ToNumber()
+				if numArg.Type != ArgNumber {
+					continue
+				}
+				summer += math.Pow((numArg.Number-mean.Number)/stdDev.Number, 3)
+				count++
+			}
+		}
+	}
+	if count > 2 {
+		return newNumberFormulaArg(summer * (count / ((count - 1) * (count - 2))))
+	}
+	return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
+}
+
 // SMALL function returns the k'th smallest value from an array of numeric
 // values. The syntax of the function is:
 //

+ 26 - 0
calc_test.go

@@ -509,10 +509,18 @@ func TestCalcCellValue(t *testing.T) {
 		"=STDEV(MUNIT(2))":      "0.577350269189626",
 		"=STDEV(0,INT(0))":      "0",
 		"=STDEV(INT(1),INT(1))": "0",
+		// STDEV.S
+		"=STDEV.S(F2:F9)": "10724.978287523809",
 		// STDEVA
 		"=STDEVA(F2:F9)":    "10724.978287523809",
 		"=STDEVA(MUNIT(2))": "0.577350269189626",
 		"=STDEVA(0,INT(0))": "0",
+		// POISSON.DIST
+		"=POISSON.DIST(20,25,FALSE)": "0.051917468608491",
+		"=POISSON.DIST(35,40,TRUE)":  "0.242414197690103",
+		// POISSON
+		"=POISSON(20,25,FALSE)": "0.051917468608491",
+		"=POISSON(35,40,TRUE)":  "0.242414197690103",
 		// SUM
 		"=SUM(1,2)":                           "3",
 		`=SUM("",1,2)`:                        "3",
@@ -676,6 +684,10 @@ func TestCalcCellValue(t *testing.T) {
 		"=PERMUT(6,6)":  "720",
 		"=PERMUT(7,6)":  "5040",
 		"=PERMUT(10,6)": "151200",
+		// SKEW
+		"=SKEW(1,2,3,4,3)": "-0.404796008910937",
+		"=SKEW(A1:B2)":     "0",
+		"=SKEW(A1:D3)":     "0",
 		// SMALL
 		"=SMALL(A1:A5,1)": "0",
 		"=SMALL(A1:B5,2)": "1",
@@ -1345,9 +1357,19 @@ func TestCalcCellValue(t *testing.T) {
 		// STDEV
 		"=STDEV()":      "STDEV requires at least 1 argument",
 		"=STDEV(E2:E9)": "#DIV/0!",
+		// STDEV.S
+		"=STDEV.S()": "STDEV.S requires at least 1 argument",
 		// STDEVA
 		"=STDEVA()":      "STDEVA requires at least 1 argument",
 		"=STDEVA(E2:E9)": "#DIV/0!",
+		// POISSON.DIST
+		"=POISSON.DIST()": "POISSON.DIST requires 3 arguments",
+		// POISSON
+		"=POISSON()":             "POISSON requires 3 arguments",
+		"=POISSON(\"\",0,FALSE)": "strconv.ParseFloat: parsing \"\": invalid syntax",
+		"=POISSON(0,\"\",FALSE)": "strconv.ParseFloat: parsing \"\": invalid syntax",
+		"=POISSON(0,0,\"\")":     "strconv.ParseBool: parsing \"\": invalid syntax",
+		"=POISSON(0,-1,TRUE)":    "#N/A",
 		// SUM
 		"=SUM((":   "formula not valid",
 		"=SUM(-)":  "formula not valid",
@@ -1456,6 +1478,10 @@ func TestCalcCellValue(t *testing.T) {
 		"=PERMUT(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
 		"=PERMUT(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
 		"=PERMUT(6,8)":    "#N/A",
+		// SKEW
+		"=SKEW()":     "SKEW requires at least 1 argument",
+		"=SKEW(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
+		"=SKEW(0)":    "#DIV/0!",
 		// SMALL
 		"=SMALL()":           "SMALL requires 2 arguments",
 		"=SMALL(A1:A5,0)":    "k should be > 0",