From 6e812a27c6e74a141e301c0f19484743ea437c52 Mon Sep 17 00:00:00 2001 From: xuri Date: Fri, 2 Apr 2021 22:41:33 +0800 Subject: [PATCH] #65 fn: BESSELI and BESSELJ --- calc.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ calc_test.go | 13 ++++++++++++ 2 files changed, 73 insertions(+) diff --git a/calc.go b/calc.go index 9396fa2..3098e48 100644 --- a/calc.go +++ b/calc.go @@ -227,6 +227,8 @@ var tokenPriority = map[string]int{ // AVERAGE // AVERAGEA // BASE +// BESSELI +// BESSELJ // BIN2DEC // BIN2HEX // BIN2OCT @@ -1226,6 +1228,64 @@ func formulaCriteriaEval(val string, criteria *formulaCriteria) (result bool, er // Engineering Functions +// BESSELI function the modified Bessel function, which is equivalent to the +// Bessel function evaluated for purely imaginary arguments. The syntax of +// the Besseli function is: +// +// BESSELI(x,n) +// +func (fn *formulaFuncs) BESSELI(argsList *list.List) formulaArg { + if argsList.Len() != 2 { + return newErrorFormulaArg(formulaErrorVALUE, "BESSELI requires 2 numeric arguments") + } + return fn.bassel(argsList, true) +} + +// BESSELJ function returns the Bessel function, Jn(x), for a specified order +// and value of x. The syntax of the function is: +// +// BESSELJ(x,n) +// +func (fn *formulaFuncs) BESSELJ(argsList *list.List) formulaArg { + if argsList.Len() != 2 { + return newErrorFormulaArg(formulaErrorVALUE, "BESSELJ requires 2 numeric arguments") + } + return fn.bassel(argsList, false) +} + +// bassel is an implementation of the formula function BESSELI and BESSELJ. +func (fn *formulaFuncs) bassel(argsList *list.List, modfied bool) formulaArg { + x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber() + if x.Type != ArgNumber { + return x + } + if n.Type != ArgNumber { + return n + } + max, x1 := 100, x.Number*0.5 + x2 := x1 * x1 + x1 = math.Pow(x1, n.Number) + n1, n2, n3, n4, add := fact(n.Number), 1.0, 0.0, n.Number, false + result := x1 / n1 + t := result * 0.9 + for result != t && max != 0 { + x1 *= x2 + n3++ + n1 *= n3 + n4++ + n2 *= n4 + t = result + if modfied || add { + result += (x1 / n1 / n2) + } else { + result -= (x1 / n1 / n2) + } + max-- + add = !add + } + return newNumberFormulaArg(result) +} + // BIN2DEC function converts a Binary (a base-2 number) into a decimal number. // The syntax of the function is: // diff --git a/calc_test.go b/calc_test.go index c4f1924..04f95bc 100644 --- a/calc_test.go +++ b/calc_test.go @@ -47,6 +47,11 @@ func TestCalcCellValue(t *testing.T) { "=2>=3": "FALSE", "=1&2": "12", // Engineering Functions + // BESSELI + "=BESSELI(4.5,1)": "15.389222753735925", + "=BESSELI(32,1)": "5.502845511211247e+12", + // BESSELJ + "=BESSELJ(1.9,2)": "0.329925727692387", // BIN2DEC "=BIN2DEC(\"10\")": "2", "=BIN2DEC(\"11\")": "3", @@ -1008,6 +1013,14 @@ func TestCalcCellValue(t *testing.T) { mathCalcError := map[string]string{ "=1/0": "#DIV/0!", // Engineering Functions + // BESSELI + "=BESSELI()": "BESSELI requires 2 numeric arguments", + "=BESSELI(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=BESSELI(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + // BESSELJ + "=BESSELJ()": "BESSELJ requires 2 numeric arguments", + "=BESSELJ(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=BESSELJ(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", // BIN2DEC "=BIN2DEC()": "BIN2DEC requires 1 numeric argument", "=BIN2DEC(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",