Skip to content

Commit 08c8da0

Browse files
authored
Fix formula calculate accuracy for functions IMSECH, IMSQRT, CHIINV, CHISQ.DIST and NEGBINOM.DIST (#1403)
- Update unit tests
1 parent 0aec9b7 commit 08c8da0

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

calc.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3345,10 +3345,12 @@ func (fn *formulaFuncs) IMCSCH(argsList *list.List) formulaArg {
33453345
if err != nil {
33463346
return newErrorFormulaArg(formulaErrorNUM, err.Error())
33473347
}
3348-
num := 1 / cmplx.Sinh(inumber)
3349-
if cmplx.IsInf(num) {
3348+
x, y := real(inumber), imag(inumber)
3349+
denom := (math.Cosh(2*x) - math.Cos(2*y)) / 2
3350+
if denom == 0 {
33503351
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
33513352
}
3353+
num := complex(math.Sinh(x)*math.Cos(y)/denom, -(math.Cosh(x)*math.Sin(y))/denom)
33523354
return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
33533355
}
33543356

@@ -3562,7 +3564,12 @@ func (fn *formulaFuncs) IMSECH(argsList *list.List) formulaArg {
35623564
if err != nil {
35633565
return newErrorFormulaArg(formulaErrorNUM, err.Error())
35643566
}
3565-
return newStringFormulaArg(cmplx2str(1/cmplx.Cosh(inumber), value[len(value)-1:]))
3567+
a, b := real(inumber), imag(inumber)
3568+
cosb := math.Cos(b)
3569+
sinha := math.Sinh(a)
3570+
denom := cosb*cosb + sinha*sinha
3571+
result := complex(math.Cosh(a)*cosb/denom, -sinha*math.Sin(b)/denom)
3572+
return newStringFormulaArg(cmplx2str(result, value[len(value)-1:]))
35663573
}
35673574

35683575
// IMSIN function returns the Sine of a supplied complex number. The syntax of
@@ -3610,7 +3617,13 @@ func (fn *formulaFuncs) IMSQRT(argsList *list.List) formulaArg {
36103617
if err != nil {
36113618
return newErrorFormulaArg(formulaErrorNUM, err.Error())
36123619
}
3613-
return newStringFormulaArg(cmplx2str(cmplx.Sqrt(inumber), value[len(value)-1:]))
3620+
a, b := real(inumber), imag(inumber)
3621+
mod := math.Hypot(a, b)
3622+
sqrtMod := math.Sqrt(mod)
3623+
arg := math.Atan2(b, a)
3624+
re := sqrtMod * math.Cos(arg/2)
3625+
im := sqrtMod * math.Sin(arg/2)
3626+
return newStringFormulaArg(cmplx2str(complex(re, im), value[len(value)-1:]))
36143627
}
36153628

36163629
// IMSUB function calculates the difference between two complex numbers
@@ -7127,7 +7140,7 @@ func incompleteGamma(a, x float64) float64 {
71277140
}
71287141
summer += math.Pow(x, float64(n)) / divisor
71297142
}
7130-
return math.Pow(x, a) * math.Exp(0-x) * summer
7143+
return math.Exp(math.FMA(a, math.Log(x), -x)) * summer
71317144
}
71327145

71337146
// binomCoeff implement binomial coefficient calculation.
@@ -7533,7 +7546,7 @@ func getLogGamma(fZ float64) float64 {
75337546

75347547
// getLowRegIGamma returns lower regularized incomplete gamma function.
75357548
func getLowRegIGamma(fA, fX float64) float64 {
7536-
lnFactor := fA*math.Log(fX) - fX - getLogGamma(fA)
7549+
lnFactor := math.FMA(fA, math.Log(fX), -fX) - getLogGamma(fA)
75377550
factor := math.Exp(lnFactor)
75387551
if fX > fA+1 {
75397552
return 1 - factor*getGammaContFraction(fA, fX)
@@ -7546,6 +7559,9 @@ func getChiSqDistCDF(fX, fDF float64) float64 {
75467559
if fX <= 0 {
75477560
return 0
75487561
}
7562+
if fDF == 1 {
7563+
return math.Erf(math.Sqrt(fX / 2))
7564+
}
75497565
return getLowRegIGamma(fDF/2, fX/2)
75507566
}
75517567

calc_test.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,6 @@ func TestCalcCellValue(t *testing.T) {
307307
"IMCOT(COMPLEX(1,-1))": "0.217621561854403+0.868014142895925i",
308308
// IMCSC
309309
"IMCSC(\"j\")": "-0.850918128239322j",
310-
// IMCSCH
311-
"IMCSCH(COMPLEX(1,-1))": "0.303931001628426+0.621518017170428i",
312310
// IMDIV
313311
"IMDIV(\"5+2i\",\"1+i\")": "3.5-1.5i",
314312
"IMDIV(\"2+2i\",\"2+i\")": "1.2+0.4i",
@@ -341,9 +339,10 @@ func TestCalcCellValue(t *testing.T) {
341339
"IMSEC(COMPLEX(1,-1))": "0.498337030555187-0.591083841721045i",
342340
// IMSECH
343341
"IMSECH(0.5)": "0.886818883970074",
344-
"IMSECH(\"3+0.5i\")": "0.0873665779621303-0.0474925494901607i",
342+
"IMSECH(\"3+0.5i\")": "0.0873665779621302-0.0474925494901607i",
345343
"IMSECH(\"2-i\")": "0.151176298265577+0.226973675393722i",
346344
"IMSECH(COMPLEX(1,-1))": "0.498337030555187+0.591083841721045i",
345+
"IMCSCH(COMPLEX(1,-1))": "0.303931001628426+0.621518017170429i",
347346
// IMSIN
348347
"IMSIN(0.5)": "0.479425538604203",
349348
"IMSIN(\"3+0.5i\")": "0.15913058529844-0.515880442452527i",
@@ -356,9 +355,9 @@ func TestCalcCellValue(t *testing.T) {
356355
"IMSINH(\"2-i\")": "1.95960104142161-3.16577851321617i",
357356
"IMSINH(COMPLEX(1,-1))": "0.634963914784736-1.29845758141598i",
358357
// IMSQRT
359-
"IMSQRT(\"i\")": "0.707106781186548+0.707106781186548i",
358+
"IMSQRT(\"i\")": "0.707106781186548+0.707106781186547i",
360359
"IMSQRT(\"2-i\")": "1.45534669022535-0.343560749722512i",
361-
"IMSQRT(\"5+2i\")": "2.27872385417085+0.438842116902254i",
360+
"IMSQRT(\"5+2i\")": "2.27872385417085+0.438842116902255i",
362361
"IMSQRT(6)": "2.44948974278318",
363362
"IMSQRT(\"-2-4i\")": "1.11178594050284-1.79890743994787i",
364363
// IMSUB
@@ -1023,6 +1022,7 @@ func TestCalcCellValue(t *testing.T) {
10231022
"CHIINV(0.75,1)": "0.101531044267622",
10241023
"CHIINV(0.1,2)": "4.60517018598809",
10251024
"CHIINV(0.8,2)": "0.446287102628419",
1025+
"CHIINV(0.25,3)": "4.10834493563232",
10261026
// CHISQ.DIST
10271027
"CHISQ.DIST(0,2,TRUE)": "0",
10281028
"CHISQ.DIST(4,1,TRUE)": "0.954499736103642",
@@ -1032,6 +1032,9 @@ func TestCalcCellValue(t *testing.T) {
10321032
"CHISQ.DIST(2,3,FALSE)": "0.207553748710297",
10331033
"CHISQ.DIST(1425,1,FALSE)": "3.88315098887099E-312",
10341034
"CHISQ.DIST(3,2,TRUE)": "0.77686983985157",
1035+
"CHISQ.DIST(8,2,TRUE)": "0.981684361111266",
1036+
"CHISQ.DIST(8,3,TRUE)": "0.953988294310769",
1037+
"CHISQ.DIST(10,4,TRUE)": "0.959572318005487",
10351038
// CHISQ.DIST.RT
10361039
"CHISQ.DIST.RT(0.5,3)": "0.918891411654676",
10371040
"CHISQ.DIST.RT(8,3)": "0.0460117056892314",
@@ -1043,6 +1046,7 @@ func TestCalcCellValue(t *testing.T) {
10431046
"CHISQ.INV(0.1,2)": "0.210721031315653",
10441047
"CHISQ.INV(0.8,2)": "3.2188758248682",
10451048
"CHISQ.INV(0.25,3)": "1.21253290304567",
1049+
"CHISQ.INV(0.5,1)": "0.454936423119573",
10461050
// CHISQ.INV.RT
10471051
"CHISQ.INV.RT(0.75,1)": "0.101531044267622",
10481052
"CHISQ.INV.RT(0.1,2)": "4.60517018598809",
@@ -1128,8 +1132,9 @@ func TestCalcCellValue(t *testing.T) {
11281132
"GAMMALN(4.5)": "2.45373657084244",
11291133
"GAMMALN(INT(1))": "0",
11301134
// GAMMALN.PRECISE
1131-
"GAMMALN.PRECISE(0.4)": "0.796677817701784",
1132-
"GAMMALN.PRECISE(4.5)": "2.45373657084244",
1135+
"GAMMALN.PRECISE(0.4)": "0.796677817701784",
1136+
"GAMMALN.PRECISE(0.75)": "0.203280951431295",
1137+
"GAMMALN.PRECISE(4.5)": "2.45373657084244",
11331138
// GAUSS
11341139
"GAUSS(-5)": "-0.499999713348428",
11351140
"GAUSS(0)": "0",
@@ -1209,6 +1214,7 @@ func TestCalcCellValue(t *testing.T) {
12091214
"NEGBINOM.DIST(15,12,0.5,FALSE)": "0.057564377784729",
12101215
"NEGBINOM.DIST(12,12,0.5,TRUE)": "0.58059012889862",
12111216
"NEGBINOM.DIST(15,12,0.5,TRUE)": "0.778965830802917",
1217+
"NEGBINOM.DIST(6,12,0.5,TRUE)": "0.118942260742188",
12121218
// NEGBINOMDIST
12131219
"NEGBINOMDIST(6,12,0.5)": "0.047210693359375",
12141220
"NEGBINOMDIST(12,12,0.5)": "0.0805901288986206",

0 commit comments

Comments
 (0)