forked from p30928647/excelize
ref #65, new formula functions: F.TEST and FTEST
This commit is contained in:
parent
46336bc788
commit
0030e800ca
81
calc.go
81
calc.go
|
@ -443,6 +443,8 @@ type formulaFuncs struct {
|
|||
// FLOOR.MATH
|
||||
// FLOOR.PRECISE
|
||||
// FORMULATEXT
|
||||
// F.TEST
|
||||
// FTEST
|
||||
// FV
|
||||
// FVSCHEDULE
|
||||
// GAMMA
|
||||
|
@ -6468,7 +6470,7 @@ func getGammaContFraction(fA, fX float64) float64 {
|
|||
fQk = math.Nextafter(f3, f3) - math.Nextafter(f4, f4)
|
||||
)
|
||||
if fQk != 0 {
|
||||
var fR = fPk / fQk
|
||||
fR := fPk / fQk
|
||||
bFinished = math.Abs((fApprox-fR)/fR) <= fHalfMachEps
|
||||
fApprox = fR
|
||||
}
|
||||
|
@ -6486,8 +6488,8 @@ func getGammaContFraction(fA, fX float64) float64 {
|
|||
|
||||
// getLogGammaHelper is a part of implementation of the function getLogGamma.
|
||||
func getLogGammaHelper(fZ float64) float64 {
|
||||
var _fg = 6.024680040776729583740234375
|
||||
var zgHelp = fZ + _fg - 0.5
|
||||
_fg := 6.024680040776729583740234375
|
||||
zgHelp := fZ + _fg - 0.5
|
||||
return math.Log(getLanczosSum(fZ)) + (fZ-0.5)*math.Log(zgHelp) - zgHelp
|
||||
}
|
||||
|
||||
|
@ -6511,7 +6513,7 @@ func getGammaHelper(fZ float64) float64 {
|
|||
|
||||
// getLogGamma calculates the natural logarithm of the gamma function.
|
||||
func getLogGamma(fZ float64) float64 {
|
||||
var fMaxGammaArgument = 171.624376956302
|
||||
fMaxGammaArgument := 171.624376956302
|
||||
if fZ >= fMaxGammaArgument {
|
||||
return getLogGammaHelper(fZ)
|
||||
}
|
||||
|
@ -7578,6 +7580,77 @@ func (fn *formulaFuncs) FINV(argsList *list.List) formulaArg {
|
|||
return newNumberFormulaArg((1/calcBetainv(1-(1-probability.Number), d2.Number/2, d1.Number/2, 0, 1) - 1) * (d2.Number / d1.Number))
|
||||
}
|
||||
|
||||
// FdotTEST function returns the F-Test for two supplied arrays. I.e. the
|
||||
// function returns the two-tailed probability that the variances in the two
|
||||
// supplied arrays are not significantly different. The syntax of the Ftest
|
||||
// function is:
|
||||
//
|
||||
// F.TEST(array1,array2)
|
||||
//
|
||||
func (fn *formulaFuncs) FdotTEST(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 2 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "F.TEST requires 2 arguments")
|
||||
}
|
||||
array1 := argsList.Front().Value.(formulaArg)
|
||||
array2 := argsList.Back().Value.(formulaArg)
|
||||
left, right := array1.ToList(), array2.ToList()
|
||||
collectMatrix := func(args []formulaArg) (n, accu float64) {
|
||||
var p, sum float64
|
||||
for _, arg := range args {
|
||||
if num := arg.ToNumber(); num.Type == ArgNumber {
|
||||
x := num.Number - p
|
||||
y := x / (n + 1)
|
||||
p += y
|
||||
accu += n * x * y
|
||||
n++
|
||||
sum += num.Number
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
nums, accu := collectMatrix(left)
|
||||
f3 := nums - 1
|
||||
if nums == 1 {
|
||||
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
||||
}
|
||||
f1 := accu / (nums - 1)
|
||||
if f1 == 0 {
|
||||
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
||||
}
|
||||
nums, accu = collectMatrix(right)
|
||||
f4 := nums - 1
|
||||
if nums == 1 {
|
||||
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
||||
}
|
||||
f2 := accu / (nums - 1)
|
||||
if f2 == 0 {
|
||||
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
||||
}
|
||||
args := list.New()
|
||||
args.PushBack(newNumberFormulaArg(f1 / f2))
|
||||
args.PushBack(newNumberFormulaArg(f3))
|
||||
args.PushBack(newNumberFormulaArg(f4))
|
||||
probability := (1 - fn.FDIST(args).Number) * 2
|
||||
if probability > 1 {
|
||||
probability = 2 - probability
|
||||
}
|
||||
return newNumberFormulaArg(probability)
|
||||
}
|
||||
|
||||
// FTEST function returns the F-Test for two supplied arrays. I.e. the function
|
||||
// returns the two-tailed probability that the variances in the two supplied
|
||||
// arrays are not significantly different. The syntax of the Ftest function
|
||||
// is:
|
||||
//
|
||||
// FTEST(array1,array2)
|
||||
//
|
||||
func (fn *formulaFuncs) FTEST(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 2 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "FTEST requires 2 arguments")
|
||||
}
|
||||
return fn.FdotTEST(argsList)
|
||||
}
|
||||
|
||||
// LOGINV function calculates the inverse of the Cumulative Log-Normal
|
||||
// Distribution Function of x, for a supplied probability. The syntax of the
|
||||
// function is:
|
||||
|
|
45
calc_test.go
45
calc_test.go
|
@ -4292,6 +4292,51 @@ func TestCalcCHITESTandCHISQdotTEST(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCalcFTEST(t *testing.T) {
|
||||
cellData := [][]interface{}{
|
||||
{"Group 1", "Group 2"},
|
||||
{3.5, 9.2},
|
||||
{4.7, 8.2},
|
||||
{6.2, 7.3},
|
||||
{4.9, 6.1},
|
||||
{3.8, 5.4},
|
||||
{5.5, 7.8},
|
||||
{7.1, 5.9},
|
||||
{6.7, 8.4},
|
||||
{3.9, 7.7},
|
||||
{4.6, 6.6},
|
||||
}
|
||||
f := prepareCalcData(cellData)
|
||||
formulaList := map[string]string{
|
||||
"=FTEST(A2:A11,B2:B11)": "0.95403555939413",
|
||||
"=F.TEST(A2:A11,B2:B11)": "0.95403555939413",
|
||||
}
|
||||
for formula, expected := range formulaList {
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||
assert.NoError(t, err, formula)
|
||||
assert.Equal(t, expected, result, formula)
|
||||
}
|
||||
calcError := map[string]string{
|
||||
"=FTEST()": "FTEST requires 2 arguments",
|
||||
"=FTEST(A2:A2,B2:B2)": "#DIV/0!",
|
||||
"=FTEST(A12:A14,B2:B4)": "#DIV/0!",
|
||||
"=FTEST(A2:A4,B2:B2)": "#DIV/0!",
|
||||
"=FTEST(A2:A4,B12:B14)": "#DIV/0!",
|
||||
"=F.TEST()": "F.TEST requires 2 arguments",
|
||||
"=F.TEST(A2:A2,B2:B2)": "#DIV/0!",
|
||||
"=F.TEST(A12:A14,B2:B4)": "#DIV/0!",
|
||||
"=F.TEST(A2:A4,B2:B2)": "#DIV/0!",
|
||||
"=F.TEST(A2:A4,B12:B14)": "#DIV/0!",
|
||||
}
|
||||
for formula, expected := range calcError {
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
|
||||
result, err := f.CalcCellValue("Sheet1", "C1")
|
||||
assert.EqualError(t, err, expected, formula)
|
||||
assert.Equal(t, "", result, formula)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalcIRR(t *testing.T) {
|
||||
cellData := [][]interface{}{{-1}, {0.2}, {0.24}, {0.288}, {0.3456}, {0.4147}}
|
||||
f := prepareCalcData(cellData)
|
||||
|
|
Loading…
Reference in New Issue