summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--calc.go35
-rw-r--r--calc_test.go7
-rw-r--r--styles.go4
-rw-r--r--xmlStyles.go4
4 files changed, 46 insertions, 4 deletions
diff --git a/calc.go b/calc.go
index 8be52c7..04d0f8b 100644
--- a/calc.go
+++ b/calc.go
@@ -282,6 +282,7 @@ var tokenPriority = map[string]int{
// GAMMA
// GAMMALN
// GCD
+// HARMEAN
// HEX2BIN
// HEX2DEC
// HEX2OCT
@@ -3927,6 +3928,40 @@ func (fn *formulaFuncs) GAMMALN(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument")
}
+// HARMEAN function calculates the harmonic mean of a supplied set of values.
+// The syntax of the function is:
+//
+// HARMEAN(number1,[number2],...)
+//
+func (fn *formulaFuncs) HARMEAN(argsList *list.List) formulaArg {
+ if argsList.Len() < 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "HARMEAN requires at least 1 argument")
+ }
+ if min := fn.MIN(argsList); min.Number < 0 {
+ return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
+ }
+ number, val, cnt := 0.0, 0.0, 0.0
+ for token := argsList.Front(); token != nil; token = token.Next() {
+ arg := token.Value.(formulaArg)
+ switch arg.Type {
+ case ArgString:
+ num := arg.ToNumber()
+ if num.Type != ArgNumber {
+ continue
+ }
+ number = num.Number
+ case ArgNumber:
+ number = arg.Number
+ }
+ if number <= 0 {
+ return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
+ }
+ val += (1 / number)
+ cnt++
+ }
+ return newNumberFormulaArg(1 / (val / cnt))
+}
+
// KURT function calculates the kurtosis of a supplied set of values. The
// syntax of the function is:
//
diff --git a/calc_test.go b/calc_test.go
index f8397e7..65f7ce1 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -605,6 +605,9 @@ func TestCalcCellValue(t *testing.T) {
// GAMMALN
"=GAMMALN(4.5)": "2.453736570842443",
"=GAMMALN(INT(1))": "0",
+ // HARMEAN
+ "=HARMEAN(2.5,3,0.5,1,3)": "1.229508196721312",
+ "=HARMEAN(\"2.5\",3,0.5,1,INT(3),\"\")": "1.229508196721312",
// KURT
"=KURT(F1:F9)": "-1.033503502551368",
"=KURT(F1,F2:F9)": "-1.033503502551368",
@@ -1393,6 +1396,10 @@ func TestCalcCellValue(t *testing.T) {
"=GAMMALN(F1)": "GAMMALN requires 1 numeric argument",
"=GAMMALN(0)": "#N/A",
"=GAMMALN(INT(0))": "#N/A",
+ // HARMEAN
+ "=HARMEAN()": "HARMEAN requires at least 1 argument",
+ "=HARMEAN(-1)": "#N/A",
+ "=HARMEAN(0)": "#N/A",
// KURT
"=KURT()": "KURT requires at least 1 argument",
"=KURT(F1,INT(1))": "#DIV/0!",
diff --git a/styles.go b/styles.go
index 06215f3..9e37239 100644
--- a/styles.go
+++ b/styles.go
@@ -2472,8 +2472,8 @@ func newAlignment(style *Style) *xlsxAlignment {
func newProtection(style *Style) *xlsxProtection {
var protection xlsxProtection
if style.Protection != nil {
- protection.Hidden = style.Protection.Hidden
- protection.Locked = style.Protection.Locked
+ protection.Hidden = &style.Protection.Hidden
+ protection.Locked = &style.Protection.Locked
}
return &protection
}
diff --git a/xmlStyles.go b/xmlStyles.go
index db85b15..0670b59 100644
--- a/xmlStyles.go
+++ b/xmlStyles.go
@@ -49,8 +49,8 @@ type xlsxAlignment struct {
// set. The cell protection properties do not take effect unless the sheet has
// been protected.
type xlsxProtection struct {
- Hidden bool `xml:"hidden,attr"`
- Locked bool `xml:"locked,attr"`
+ Hidden *bool `xml:"hidden,attr"`
+ Locked *bool `xml:"locked,attr"`
}
// xlsxLine expresses a single set of cell border.