Skip to content

Commit 5bf4bce

Browse files
committed
ref qax-os#65, qax-os#1196: fix the compatibility issue and added new formula function
- New formula functions: MODE and T.TEST
1 parent 26174a2 commit 5bf4bce

File tree

4 files changed

+138
-22
lines changed

4 files changed

+138
-22
lines changed

calc.go

+61
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ type formulaFuncs struct {
549549
// MINUTE
550550
// MIRR
551551
// MOD
552+
// MODE
552553
// MONTH
553554
// MROUND
554555
// MULTINOMIAL
@@ -673,6 +674,7 @@ type formulaFuncs struct {
673674
// TRIMMEAN
674675
// TRUE
675676
// TRUNC
677+
// T.TEST
676678
// TTEST
677679
// TYPE
678680
// UNICHAR
@@ -7974,6 +7976,51 @@ func (fn *formulaFuncs) LOGNORMDIST(argsList *list.List) formulaArg {
79747976
return fn.NORMSDIST(args)
79757977
}
79767978

7979+
// MODE function returns the statistical mode (the most frequently occurring
7980+
// value) of a list of supplied numbers. If there are 2 or more most
7981+
// frequently occurring values in the supplied data, the function returns the
7982+
// lowest of these values The syntax of the function is:
7983+
//
7984+
// MODE(number1,[number2],...)
7985+
//
7986+
func (fn *formulaFuncs) MODE(argsList *list.List) formulaArg {
7987+
if argsList.Len() < 1 {
7988+
return newErrorFormulaArg(formulaErrorVALUE, "MODE requires at least 1 argument")
7989+
}
7990+
var values []float64
7991+
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
7992+
cells := arg.Value.(formulaArg)
7993+
if cells.Type != ArgMatrix && cells.ToNumber().Type != ArgNumber {
7994+
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
7995+
}
7996+
for _, cell := range cells.ToList() {
7997+
if num := cell.ToNumber(); num.Type == ArgNumber {
7998+
values = append(values, num.Number)
7999+
}
8000+
}
8001+
}
8002+
sort.Float64s(values)
8003+
cnt := len(values)
8004+
var count, modeCnt int
8005+
var mode float64
8006+
for i := 0; i < cnt; i++ {
8007+
count = 0
8008+
for j := 0; j < cnt; j++ {
8009+
if j != i && values[j] == values[i] {
8010+
count++
8011+
}
8012+
}
8013+
if count > modeCnt {
8014+
modeCnt = count
8015+
mode = values[i]
8016+
}
8017+
}
8018+
if modeCnt == 0 {
8019+
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
8020+
}
8021+
return newNumberFormulaArg(mode)
8022+
}
8023+
79778024
// NEGBINOMdotDIST function calculates the probability mass function or the
79788025
// cumulative distribution function for the Negative Binomial Distribution.
79798026
// This gives the probability that there will be a given number of failures
@@ -9342,6 +9389,20 @@ func (fn *formulaFuncs) TTEST(argsList *list.List) formulaArg {
93429389
return fn.tTest(array1.Matrix, array2.Matrix, tails.Number, typeArg.Number)
93439390
}
93449391

9392+
// TdotTEST function calculates the probability associated with the Student's T
9393+
// Test, which is commonly used for identifying whether two data sets are
9394+
// likely to have come from the same two underlying populations with the same
9395+
// mean. The syntax of the function is:
9396+
//
9397+
// T.TEST(array1,array2,tails,type)
9398+
//
9399+
func (fn *formulaFuncs) TdotTEST(argsList *list.List) formulaArg {
9400+
if argsList.Len() != 4 {
9401+
return newErrorFormulaArg(formulaErrorVALUE, "T.TEST requires 4 arguments")
9402+
}
9403+
return fn.TTEST(argsList)
9404+
}
9405+
93459406
// TRIMMEAN function calculates the trimmed mean (or truncated mean) of a
93469407
// supplied set of values. The syntax of the function is:
93479408
//

calc_test.go

+73-18
Original file line numberDiff line numberDiff line change
@@ -4865,6 +4865,43 @@ func TestCalcISFORMULA(t *testing.T) {
48654865
}
48664866
}
48674867

4868+
func TestCalcMODE(t *testing.T) {
4869+
cellData := [][]interface{}{
4870+
{1, 1},
4871+
{1, 1},
4872+
{2, 2},
4873+
{2, 2},
4874+
{3, 2},
4875+
{3},
4876+
{3},
4877+
{4},
4878+
{4},
4879+
{4},
4880+
}
4881+
f := prepareCalcData(cellData)
4882+
formulaList := map[string]string{
4883+
"=MODE(A1:A10)": "3",
4884+
"=MODE(B1:B6)": "2",
4885+
}
4886+
for formula, expected := range formulaList {
4887+
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
4888+
result, err := f.CalcCellValue("Sheet1", "C1")
4889+
assert.NoError(t, err, formula)
4890+
assert.Equal(t, expected, result, formula)
4891+
}
4892+
calcError := map[string]string{
4893+
"=MODE()": "MODE requires at least 1 argument",
4894+
"=MODE(0,\"\")": "#VALUE!",
4895+
"=MODE(D1:D3)": "#N/A",
4896+
}
4897+
for formula, expected := range calcError {
4898+
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
4899+
result, err := f.CalcCellValue("Sheet1", "C1")
4900+
assert.EqualError(t, err, expected, formula)
4901+
assert.Equal(t, "", result, formula)
4902+
}
4903+
}
4904+
48684905
func TestCalcSHEET(t *testing.T) {
48694906
f := NewFile()
48704907
f.NewSheet("Sheet2")
@@ -4914,12 +4951,18 @@ func TestCalcTTEST(t *testing.T) {
49144951
}
49154952
f := prepareCalcData(cellData)
49164953
formulaList := map[string]string{
4917-
"=TTEST(A1:A12,B1:B12,1,1)": "0.44907068944428",
4918-
"=TTEST(A1:A12,B1:B12,1,2)": "0.436717306029283",
4919-
"=TTEST(A1:A12,B1:B12,1,3)": "0.436722015384755",
4920-
"=TTEST(A1:A12,B1:B12,2,1)": "0.898141378888559",
4921-
"=TTEST(A1:A12,B1:B12,2,2)": "0.873434612058567",
4922-
"=TTEST(A1:A12,B1:B12,2,3)": "0.873444030769511",
4954+
"=TTEST(A1:A12,B1:B12,1,1)": "0.44907068944428",
4955+
"=TTEST(A1:A12,B1:B12,1,2)": "0.436717306029283",
4956+
"=TTEST(A1:A12,B1:B12,1,3)": "0.436722015384755",
4957+
"=TTEST(A1:A12,B1:B12,2,1)": "0.898141378888559",
4958+
"=TTEST(A1:A12,B1:B12,2,2)": "0.873434612058567",
4959+
"=TTEST(A1:A12,B1:B12,2,3)": "0.873444030769511",
4960+
"=T.TEST(A1:A12,B1:B12,1,1)": "0.44907068944428",
4961+
"=T.TEST(A1:A12,B1:B12,1,2)": "0.436717306029283",
4962+
"=T.TEST(A1:A12,B1:B12,1,3)": "0.436722015384755",
4963+
"=T.TEST(A1:A12,B1:B12,2,1)": "0.898141378888559",
4964+
"=T.TEST(A1:A12,B1:B12,2,2)": "0.873434612058567",
4965+
"=T.TEST(A1:A12,B1:B12,2,3)": "0.873444030769511",
49234966
}
49244967
for formula, expected := range formulaList {
49254968
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))
@@ -4928,18 +4971,30 @@ func TestCalcTTEST(t *testing.T) {
49284971
assert.Equal(t, expected, result, formula)
49294972
}
49304973
calcError := map[string]string{
4931-
"=TTEST()": "TTEST requires 4 arguments",
4932-
"=TTEST(\"\",B1:B12,1,1)": "#NUM!",
4933-
"=TTEST(A1:A12,\"\",1,1)": "#NUM!",
4934-
"=TTEST(A1:A12,B1:B12,\"\",1)": "strconv.ParseFloat: parsing \"\": invalid syntax",
4935-
"=TTEST(A1:A12,B1:B12,1,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
4936-
"=TTEST(A1:A12,B1:B12,0,1)": "#NUM!",
4937-
"=TTEST(A1:A12,B1:B12,1,0)": "#NUM!",
4938-
"=TTEST(A1:A2,B1:B1,1,1)": "#N/A",
4939-
"=TTEST(A13:A14,B13:B14,1,1)": "#NUM!",
4940-
"=TTEST(A12:A13,B12:B13,1,1)": "#DIV/0!",
4941-
"=TTEST(A13:A14,B13:B14,1,2)": "#NUM!",
4942-
"=TTEST(D1:D4,E1:E4,1,3)": "#NUM!",
4974+
"=TTEST()": "TTEST requires 4 arguments",
4975+
"=TTEST(\"\",B1:B12,1,1)": "#NUM!",
4976+
"=TTEST(A1:A12,\"\",1,1)": "#NUM!",
4977+
"=TTEST(A1:A12,B1:B12,\"\",1)": "strconv.ParseFloat: parsing \"\": invalid syntax",
4978+
"=TTEST(A1:A12,B1:B12,1,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
4979+
"=TTEST(A1:A12,B1:B12,0,1)": "#NUM!",
4980+
"=TTEST(A1:A12,B1:B12,1,0)": "#NUM!",
4981+
"=TTEST(A1:A2,B1:B1,1,1)": "#N/A",
4982+
"=TTEST(A13:A14,B13:B14,1,1)": "#NUM!",
4983+
"=TTEST(A12:A13,B12:B13,1,1)": "#DIV/0!",
4984+
"=TTEST(A13:A14,B13:B14,1,2)": "#NUM!",
4985+
"=TTEST(D1:D4,E1:E4,1,3)": "#NUM!",
4986+
"=T.TEST()": "T.TEST requires 4 arguments",
4987+
"=T.TEST(\"\",B1:B12,1,1)": "#NUM!",
4988+
"=T.TEST(A1:A12,\"\",1,1)": "#NUM!",
4989+
"=T.TEST(A1:A12,B1:B12,\"\",1)": "strconv.ParseFloat: parsing \"\": invalid syntax",
4990+
"=T.TEST(A1:A12,B1:B12,1,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
4991+
"=T.TEST(A1:A12,B1:B12,0,1)": "#NUM!",
4992+
"=T.TEST(A1:A12,B1:B12,1,0)": "#NUM!",
4993+
"=T.TEST(A1:A2,B1:B1,1,1)": "#N/A",
4994+
"=T.TEST(A13:A14,B13:B14,1,1)": "#NUM!",
4995+
"=T.TEST(A12:A13,B12:B13,1,1)": "#DIV/0!",
4996+
"=T.TEST(A13:A14,B13:B14,1,2)": "#NUM!",
4997+
"=T.TEST(D1:D4,E1:E4,1,3)": "#NUM!",
49434998
}
49444999
for formula, expected := range calcError {
49455000
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula))

numfmt.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ type languageInfo struct {
3333
type numberFormat struct {
3434
section []nfp.Section
3535
t time.Time
36-
sectionIdx int
37-
isNumeric, hours, seconds bool
38-
number float64
36+
sectionIdx int
37+
isNumeric, hours, seconds bool
38+
number float64
3939
ap, afterPoint, beforePoint, localCode, result, value, valueSectionType string
4040
}
4141

xmlWorkbook.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ type xlsxWorkbook struct {
4040
FileVersion *xlsxFileVersion `xml:"fileVersion"`
4141
FileSharing *xlsxExtLst `xml:"fileSharing"`
4242
WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"`
43-
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
4443
AlternateContent *xlsxAlternateContent `xml:"mc:AlternateContent"`
4544
DecodeAlternateContent *xlsxInnerXML `xml:"http://schemas.openxmlformats.org/markup-compatibility/2006 AlternateContent"`
45+
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
4646
BookViews *xlsxBookViews `xml:"bookViews"`
4747
Sheets xlsxSheets `xml:"sheets"`
4848
FunctionGroups *xlsxExtLst `xml:"functionGroups"`

0 commit comments

Comments
 (0)