diff --git a/calc.go b/calc.go index 20d5b5e..57b2cda 100644 --- a/calc.go +++ b/calc.go @@ -374,6 +374,7 @@ type formulaFuncs struct { // CONCATENATE // CONFIDENCE // CONFIDENCE.NORM +// CONFIDENCE.T // CORREL // COS // COSH @@ -588,6 +589,7 @@ type formulaFuncs struct { // PERCENTRANK // PERMUT // PERMUTATIONA +// PHI // PI // PMT // POISSON.DIST @@ -6805,7 +6807,7 @@ func (fn *formulaFuncs) CONFIDENCE(argsList *list.List) formulaArg { // confidence value that can be used to construct the confidence interval for // a population mean, for a supplied probability and sample size. It is // assumed that the standard deviation of the population is known. The syntax -// of the Confidence.Norm function is: +// of the function is: // // CONFIDENCE.NORM(alpha,standard_dev,size) // @@ -6813,6 +6815,42 @@ func (fn *formulaFuncs) CONFIDENCEdotNORM(argsList *list.List) formulaArg { return fn.confidence("CONFIDENCE.NORM", argsList) } +// CONFIDENCEdotT function uses a Student's T-Distribution to calculate a +// confidence value that can be used to construct the confidence interval for +// a population mean, for a supplied probablity and supplied sample size. It +// is assumed that the standard deviation of the population is known. The +// syntax of the function is: +// +// CONFIDENCE.T(alpha,standard_dev,size) +// +func (fn *formulaFuncs) CONFIDENCEdotT(argsList *list.List) formulaArg { + if argsList.Len() != 3 { + return newErrorFormulaArg(formulaErrorVALUE, "CONFIDENCE.T requires 3 arguments") + } + var alpha, standardDev, size formulaArg + if alpha = argsList.Front().Value.(formulaArg).ToNumber(); alpha.Type != ArgNumber { + return alpha + } + if standardDev = argsList.Front().Next().Value.(formulaArg).ToNumber(); standardDev.Type != ArgNumber { + return standardDev + } + if size = argsList.Back().Value.(formulaArg).ToNumber(); size.Type != ArgNumber { + return size + } + if alpha.Number <= 0 || alpha.Number >= 1 || standardDev.Number <= 0 || size.Number < 1 { + return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) + } + if size.Number == 1 { + return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) + } + return newNumberFormulaArg(standardDev.Number * calcIterateInverse(calcInverseIterator{ + name: "CONFIDENCE.T", + fp: alpha.Number, + fDF: size.Number - 1, + nT: 2, + }, size.Number/2, size.Number) / math.Sqrt(size.Number)) +} + // COVAR function calculates the covariance of two supplied sets of values. The // syntax of the function is: // @@ -8891,6 +8929,22 @@ func (fn *formulaFuncs) PERMUTATIONA(argsList *list.List) formulaArg { return newNumberFormulaArg(math.Pow(num, numChosen)) } +// PHI function returns the value of the density function for a standard normal +// distribution for a supplied number. The syntax of the function is: +// +// PHI(x) +// +func (fn *formulaFuncs) PHI(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "PHI requires 1 argument") + } + x := argsList.Front().Value.(formulaArg).ToNumber() + if x.Type != ArgNumber { + return x + } + return newNumberFormulaArg(0.39894228040143268 * math.Exp(-(x.Number*x.Number)/2)) +} + // QUARTILE function returns a requested quartile of a supplied range of // values. The syntax of the function is: // @@ -13122,7 +13176,7 @@ func validateFrequency(freq float64) bool { return freq == 1 || freq == 2 || freq == 4 } -// ACCRINT function returns the accrued interest for a security that pays +// ACCRINT function returns the accrued interest in a security that pays // periodic interest. The syntax of the function is: // // ACCRINT(issue,first_interest,settlement,rate,par,frequency,[basis],[calc_method]) @@ -13166,7 +13220,7 @@ func (fn *formulaFuncs) ACCRINT(argsList *list.List) formulaArg { return newNumberFormulaArg(par.Number * rate.Number * frac1.Number) } -// ACCRINTM function returns the accrued interest for a security that pays +// ACCRINTM function returns the accrued interest in a security that pays // interest at maturity. The syntax of the function is: // // ACCRINTM(issue,settlement,rate,[par],[basis]) diff --git a/calc_test.go b/calc_test.go index 689fd92..c553d12 100644 --- a/calc_test.go +++ b/calc_test.go @@ -879,6 +879,8 @@ func TestCalcCellValue(t *testing.T) { "=CONFIDENCE(0.05,0.07,100)": "0.0137197479028414", // CONFIDENCE.NORM "=CONFIDENCE.NORM(0.05,0.07,100)": "0.0137197479028414", + // CONFIDENCE.T + "=CONFIDENCE.T(0.05,0.07,100)": "0.0138895186611049", // CORREL "=CORREL(A1:A5,B1:B5)": "1", // COUNT @@ -1122,6 +1124,11 @@ func TestCalcCellValue(t *testing.T) { // PERMUTATIONA "=PERMUTATIONA(6,6)": "46656", "=PERMUTATIONA(7,6)": "117649", + // PHI + "=PHI(-1.5)": "0.129517595665892", + "=PHI(0)": "0.398942280401433", + "=PHI(0.1)": "0.396952547477012", + "=PHI(1)": "0.241970724519143", // QUARTILE "=QUARTILE(A1:A4,2)": "1.5", // QUARTILE.EXC @@ -2643,6 +2650,16 @@ func TestCalcCellValue(t *testing.T) { "=CORREL()": "CORREL requires 2 arguments", "=CORREL(A1:A3,B1:B5)": "#N/A", "=CORREL(A1:A1,B1:B1)": "#DIV/0!", + // CONFIDENCE.T + "=CONFIDENCE.T()": "CONFIDENCE.T requires 3 arguments", + "=CONFIDENCE.T(\"\",0.07,100)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=CONFIDENCE.T(0.05,\"\",100)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=CONFIDENCE.T(0.05,0.07,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=CONFIDENCE.T(0,0.07,100)": "#NUM!", + "=CONFIDENCE.T(1,0.07,100)": "#NUM!", + "=CONFIDENCE.T(0.05,0,100)": "#NUM!", + "=CONFIDENCE.T(0.05,0.07,0)": "#NUM!", + "=CONFIDENCE.T(0.05,0.07,1)": "#DIV/0!", // COUNTBLANK "=COUNTBLANK()": "COUNTBLANK requires 1 argument", "=COUNTBLANK(1,2)": "COUNTBLANK requires 1 argument", @@ -2985,6 +3002,9 @@ func TestCalcCellValue(t *testing.T) { "=PERMUTATIONA(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=PERMUTATIONA(-1,0)": "#N/A", "=PERMUTATIONA(0,-1)": "#N/A", + // PHI + "=PHI()": "PHI requires 1 argument", + "=PHI(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", // QUARTILE "=QUARTILE()": "QUARTILE requires 2 arguments", "=QUARTILE(A1:A4,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", diff --git a/drawing.go b/drawing.go index 1daa912..d0e9135 100644 --- a/drawing.go +++ b/drawing.go @@ -957,14 +957,14 @@ func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls { // drawPlotAreaCatAx provides a function to draw the c:catAx element. func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs { - min := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Minimum)} - max := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Maximum)} - if formatSet.XAxis.Minimum == 0 { - min = nil - } - if formatSet.XAxis.Maximum == 0 { + max := &attrValFloat{Val: formatSet.XAxis.Maximum} + min := &attrValFloat{Val: formatSet.XAxis.Minimum} + if formatSet.XAxis.Maximum == nil { max = nil } + if formatSet.XAxis.Minimum == nil { + min = nil + } axs := []*cAxs{ { AxID: &attrValInt{Val: intPtr(754001152)}, @@ -1006,14 +1006,14 @@ func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs { // drawPlotAreaValAx provides a function to draw the c:valAx element. func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs { - min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)} - max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)} - if formatSet.YAxis.Minimum == 0 { - min = nil - } - if formatSet.YAxis.Maximum == 0 { + max := &attrValFloat{Val: formatSet.YAxis.Maximum} + min := &attrValFloat{Val: formatSet.YAxis.Minimum} + if formatSet.YAxis.Maximum == nil { max = nil } + if formatSet.YAxis.Minimum == nil { + min = nil + } var logBase *attrValFloat if formatSet.YAxis.LogBase >= 2 && formatSet.YAxis.LogBase <= 1000 { logBase = &attrValFloat{Val: float64Ptr(formatSet.YAxis.LogBase)} @@ -1060,14 +1060,14 @@ func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs { // drawPlotAreaSerAx provides a function to draw the c:serAx element. func (f *File) drawPlotAreaSerAx(formatSet *formatChart) []*cAxs { - min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)} - max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)} - if formatSet.YAxis.Minimum == 0 { - min = nil - } - if formatSet.YAxis.Maximum == 0 { + max := &attrValFloat{Val: formatSet.YAxis.Maximum} + min := &attrValFloat{Val: formatSet.YAxis.Minimum} + if formatSet.YAxis.Maximum == nil { max = nil } + if formatSet.YAxis.Minimum == nil { + min = nil + } return []*cAxs{ { AxID: &attrValInt{Val: intPtr(832256642)}, diff --git a/go.mod b/go.mod index 16874b2..116b7a1 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/richardlehane/mscfb v1.0.4 github.com/stretchr/testify v1.7.0 - github.com/xuri/efp v0.0.0-20220216053911-6d8731f62184 - github.com/xuri/nfp v0.0.0-20220215121256-71f1502108b5 - golang.org/x/crypto v0.0.0-20220214200702-86341886e292 + github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 + github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 + golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 golang.org/x/image v0.0.0-20211028202545-6944b10bf410 - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd + golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 golang.org/x/text v0.3.7 ) diff --git a/go.sum b/go.sum index a4051d4..8ca6233 100644 --- a/go.sum +++ b/go.sum @@ -11,17 +11,17 @@ github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTK github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/xuri/efp v0.0.0-20220216053911-6d8731f62184 h1:9nchVQT/GVLRvOnXzx+wUvSublH/jG/ANV4MxBnGhUA= -github.com/xuri/efp v0.0.0-20220216053911-6d8731f62184/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= -github.com/xuri/nfp v0.0.0-20220215121256-71f1502108b5 h1:Pg6lKJe2FUZTalbUygJxgW1ke2re9lY3YW5TKb+Pxe4= -github.com/xuri/nfp v0.0.0-20220215121256-71f1502108b5/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk= +github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M= +github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM= +golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/xmlChart.go b/xmlChart.go index 45f1ce6..b6ee3cd 100644 --- a/xmlChart.go +++ b/xmlChart.go @@ -520,23 +520,23 @@ type cPageMargins struct { // formatChartAxis directly maps the format settings of the chart axis. type formatChartAxis struct { - None bool `json:"none"` - Crossing string `json:"crossing"` - MajorGridlines bool `json:"major_grid_lines"` - MinorGridlines bool `json:"minor_grid_lines"` - MajorTickMark string `json:"major_tick_mark"` - MinorTickMark string `json:"minor_tick_mark"` - MinorUnitType string `json:"minor_unit_type"` - MajorUnit float64 `json:"major_unit"` - MajorUnitType string `json:"major_unit_type"` - TickLabelSkip int `json:"tick_label_skip"` - DisplayUnits string `json:"display_units"` - DisplayUnitsVisible bool `json:"display_units_visible"` - DateAxis bool `json:"date_axis"` - ReverseOrder bool `json:"reverse_order"` - Maximum float64 `json:"maximum"` - Minimum float64 `json:"minimum"` - NumFormat string `json:"num_format"` + None bool `json:"none"` + Crossing string `json:"crossing"` + MajorGridlines bool `json:"major_grid_lines"` + MinorGridlines bool `json:"minor_grid_lines"` + MajorTickMark string `json:"major_tick_mark"` + MinorTickMark string `json:"minor_tick_mark"` + MinorUnitType string `json:"minor_unit_type"` + MajorUnit float64 `json:"major_unit"` + MajorUnitType string `json:"major_unit_type"` + TickLabelSkip int `json:"tick_label_skip"` + DisplayUnits string `json:"display_units"` + DisplayUnitsVisible bool `json:"display_units_visible"` + DateAxis bool `json:"date_axis"` + ReverseOrder bool `json:"reverse_order"` + Maximum *float64 `json:"maximum"` + Minimum *float64 `json:"minimum"` + NumFormat string `json:"num_format"` NumFont struct { Color string `json:"color"` Bold bool `json:"bold"` diff --git a/xmlWorksheet.go b/xmlWorksheet.go index e4d52ec..eb855c5 100644 --- a/xmlWorksheet.go +++ b/xmlWorksheet.go @@ -116,7 +116,7 @@ type xlsxPageSetUp struct { FirstPageNumber string `xml:"firstPageNumber,attr,omitempty"` FitToHeight *int `xml:"fitToHeight,attr"` FitToWidth *int `xml:"fitToWidth,attr"` - HorizontalDPI float64 `xml:"horizontalDpi,attr,omitempty"` + HorizontalDPI string `xml:"horizontalDpi,attr,omitempty"` RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` Orientation string `xml:"orientation,attr,omitempty"` PageOrder string `xml:"pageOrder,attr,omitempty"` @@ -126,7 +126,7 @@ type xlsxPageSetUp struct { Scale int `xml:"scale,attr,omitempty"` UseFirstPageNumber bool `xml:"useFirstPageNumber,attr,omitempty"` UsePrinterDefaults bool `xml:"usePrinterDefaults,attr,omitempty"` - VerticalDPI float64 `xml:"verticalDpi,attr,omitempty"` + VerticalDPI string `xml:"verticalDpi,attr,omitempty"` } // xlsxPrintOptions directly maps the printOptions element in the namespace