diff --git a/calc.go b/calc.go index 951b843..9cadeb9 100644 --- a/calc.go +++ b/calc.go @@ -506,6 +506,8 @@ type formulaFuncs struct { // LOG // LOG10 // LOGINV +// LOGNORM.DIST +// LOGNORMDIST // LOGNORM.INV // LOOKUP // LOWER @@ -6473,6 +6475,72 @@ func (fn *formulaFuncs) LOGNORMdotINV(argsList *list.List) formulaArg { return fn.LOGINV(argsList) } +// LOGNORMdotDIST function calculates the Log-Normal Probability Density +// Function or the Cumulative Log-Normal Distribution Function for a supplied +// value of x. The syntax of the function is: +// +// LOGNORM.DIST(x,mean,standard_dev,cumulative) +// +func (fn *formulaFuncs) LOGNORMdotDIST(argsList *list.List) formulaArg { + if argsList.Len() != 4 { + return newErrorFormulaArg(formulaErrorVALUE, "LOGNORM.DIST requires 4 arguments") + } + var x, mean, stdDev, 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 stdDev = argsList.Back().Prev().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber { + return stdDev + } + if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError { + return cumulative + } + if x.Number <= 0 || stdDev.Number <= 0 { + return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) + } + if cumulative.Number == 1 { + args := list.New() + args.PushBack(newNumberFormulaArg((math.Log(x.Number) - mean.Number) / stdDev.Number)) + args.PushBack(newNumberFormulaArg(0)) + args.PushBack(newNumberFormulaArg(1)) + args.PushBack(cumulative) + return fn.NORMDIST(args) + } + return newNumberFormulaArg((1 / (math.Sqrt(2*math.Pi) * stdDev.Number * x.Number)) * + math.Exp(0-(math.Pow((math.Log(x.Number)-mean.Number), 2)/(2*math.Pow(stdDev.Number, 2))))) + +} + +// LOGNORMDIST function calculates the Cumulative Log-Normal Distribution +// Function at a supplied value of x. The syntax of the function is: +// +// LOGNORMDIST(x,mean,standard_dev) +// +func (fn *formulaFuncs) LOGNORMDIST(argsList *list.List) formulaArg { + if argsList.Len() != 3 { + return newErrorFormulaArg(formulaErrorVALUE, "LOGNORMDIST requires 3 arguments") + } + var x, mean, stdDev 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 stdDev = argsList.Back().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber { + return stdDev + } + if x.Number <= 0 || stdDev.Number <= 0 { + return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) + } + args := list.New() + args.PushBack(newNumberFormulaArg((math.Log(x.Number) - mean.Number) / stdDev.Number)) + return fn.NORMSDIST(args) +} + // NORMdotDIST function calculates the Normal Probability Density Function or // the Cumulative Normal Distribution. Function for a supplied set of // parameters. The syntax of the function is: diff --git a/calc_test.go b/calc_test.go index 8f1c1e5..458c381 100644 --- a/calc_test.go +++ b/calc_test.go @@ -894,6 +894,11 @@ func TestCalcCellValue(t *testing.T) { "=LOGINV(0.3,2,0.2)": "6.6533460753367", // LOGINV "=LOGNORM.INV(0.3,2,0.2)": "6.6533460753367", + // LOGNORM.DIST + "=LOGNORM.DIST(0.5,10,5,FALSE)": "0.0162104821842127", + "=LOGNORM.DIST(12,10,5,TRUE)": "0.0664171147992077", + // LOGNORMDIST + "=LOGNORMDIST(12,10,5)": "0.0664171147992077", // NORM.DIST "=NORM.DIST(0.8,1,0.3,TRUE)": "0.252492537546923", "=NORM.DIST(50,40,20,FALSE)": "0.017603266338215", @@ -2507,6 +2512,21 @@ func TestCalcCellValue(t *testing.T) { "=LOGNORM.INV(0,2,0.2)": "#NUM!", "=LOGNORM.INV(1,2,0.2)": "#NUM!", "=LOGNORM.INV(0.3,2,0)": "#NUM!", + // LOGNORM.DIST + "=LOGNORM.DIST()": "LOGNORM.DIST requires 4 arguments", + "=LOGNORM.DIST(\"\",10,5,FALSE)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORM.DIST(0.5,\"\",5,FALSE)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORM.DIST(0.5,10,\"\",FALSE)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORM.DIST(0.5,10,5,\"\")": "strconv.ParseBool: parsing \"\": invalid syntax", + "=LOGNORM.DIST(0,10,5,FALSE)": "#NUM!", + "=LOGNORM.DIST(0.5,10,0,FALSE)": "#NUM!", + // LOGNORMDIST + "=LOGNORMDIST()": "LOGNORMDIST requires 3 arguments", + "=LOGNORMDIST(\"\",10,5)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORMDIST(12,\"\",5)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORMDIST(12,10,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=LOGNORMDIST(0,2,5)": "#NUM!", + "=LOGNORMDIST(12,10,0)": "#NUM!", // NORM.DIST "=NORM.DIST()": "NORM.DIST requires 4 arguments", // NORMDIST