summaryrefslogtreecommitdiff
path: root/calc.go
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2022-03-30 00:01:38 +0800
committerxuri <xuri.me@gmail.com>2022-03-30 00:01:38 +0800
commit29d63f6ae0a3411be7e9799c80e6be41997c4f14 (patch)
tree86067ba9fd11e5b6f5800fc154f930474c1576d3 /calc.go
parent0030e800ca1e151483db96172034122c86ce97fc (diff)
ref #65, new formula functions: HYPGEOM.DIST and HYPGEOMDIST
Diffstat (limited to 'calc.go')
-rw-r--r--calc.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/calc.go b/calc.go
index 0f2003d..fc2895f 100644
--- a/calc.go
+++ b/calc.go
@@ -464,6 +464,8 @@ type formulaFuncs struct {
// HEX2OCT
// HLOOKUP
// HOUR
+// HYPGEOM.DIST
+// HYPGEOMDIST
// IF
// IFERROR
// IFNA
@@ -7328,6 +7330,90 @@ func (fn *formulaFuncs) HARMEAN(argsList *list.List) formulaArg {
return newNumberFormulaArg(1 / (val / cnt))
}
+// prepareHYPGEOMDISTArgs checking and prepare arguments for the formula
+// function HYPGEOMDIST and HYPGEOM.DIST.
+func (fn *formulaFuncs) prepareHYPGEOMDISTArgs(name string, argsList *list.List) formulaArg {
+ if name == "HYPGEOMDIST" && argsList.Len() != 4 {
+ return newErrorFormulaArg(formulaErrorVALUE, "HYPGEOMDIST requires 4 numeric arguments")
+ }
+ if name == "HYPGEOM.DIST" && argsList.Len() != 5 {
+ return newErrorFormulaArg(formulaErrorVALUE, "HYPGEOM.DIST requires 5 arguments")
+ }
+ var sampleS, numberSample, populationS, numberPop, cumulative formulaArg
+ if sampleS = argsList.Front().Value.(formulaArg).ToNumber(); sampleS.Type != ArgNumber {
+ return sampleS
+ }
+ if numberSample = argsList.Front().Next().Value.(formulaArg).ToNumber(); numberSample.Type != ArgNumber {
+ return numberSample
+ }
+ if populationS = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); populationS.Type != ArgNumber {
+ return populationS
+ }
+ if numberPop = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); numberPop.Type != ArgNumber {
+ return numberPop
+ }
+ if sampleS.Number < 0 ||
+ sampleS.Number > math.Min(numberSample.Number, populationS.Number) ||
+ sampleS.Number < math.Max(0, numberSample.Number-numberPop.Number+populationS.Number) ||
+ numberSample.Number <= 0 ||
+ numberSample.Number > numberPop.Number ||
+ populationS.Number <= 0 ||
+ populationS.Number > numberPop.Number ||
+ numberPop.Number <= 0 {
+ return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
+ }
+ if name == "HYPGEOM.DIST" {
+ if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type != ArgNumber {
+ return cumulative
+ }
+ }
+ return newListFormulaArg([]formulaArg{sampleS, numberSample, populationS, numberPop, cumulative})
+}
+
+// HYPGEOMdotDIST function returns the value of the hypergeometric distribution
+// for a specified number of successes from a population sample. The function
+// can calculate the cumulative distribution or the probability density
+// function. The syntax of the function is:
+//
+// HYPGEOM.DIST(sample_s,number_sample,population_s,number_pop,cumulative)
+//
+func (fn *formulaFuncs) HYPGEOMdotDIST(argsList *list.List) formulaArg {
+ args := fn.prepareHYPGEOMDISTArgs("HYPGEOM.DIST", argsList)
+ if args.Type != ArgList {
+ return args
+ }
+ sampleS, numberSample, populationS, numberPop, cumulative := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4]
+ if cumulative.Number == 1 {
+ var res float64
+ for i := 0; i <= int(sampleS.Number); i++ {
+ res += binomCoeff(populationS.Number, float64(i)) *
+ binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-float64(i)) /
+ binomCoeff(numberPop.Number, numberSample.Number)
+ }
+ return newNumberFormulaArg(res)
+ }
+ return newNumberFormulaArg(binomCoeff(populationS.Number, sampleS.Number) *
+ binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-sampleS.Number) /
+ binomCoeff(numberPop.Number, numberSample.Number))
+}
+
+// HYPGEOMDIST function returns the value of the hypergeometric distribution
+// for a given number of successes from a sample of a population. The syntax
+// of the function is:
+//
+// HYPGEOMDIST(sample_s,number_sample,population_s,number_pop)
+//
+func (fn *formulaFuncs) HYPGEOMDIST(argsList *list.List) formulaArg {
+ args := fn.prepareHYPGEOMDISTArgs("HYPGEOMDIST", argsList)
+ if args.Type != ArgList {
+ return args
+ }
+ sampleS, numberSample, populationS, numberPop := args.List[0], args.List[1], args.List[2], args.List[3]
+ return newNumberFormulaArg(binomCoeff(populationS.Number, sampleS.Number) *
+ binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-sampleS.Number) /
+ binomCoeff(numberPop.Number, numberSample.Number))
+}
+
// KURT function calculates the kurtosis of a supplied set of values. The
// syntax of the function is:
//