From db7b4ee36200df4b4838c2111e81808016b4f6ef Mon Sep 17 00:00:00 2001 From: xuri Date: Mon, 1 Feb 2021 00:07:51 +0800 Subject: [PATCH] update formula functions test --- calc.go | 583 ++++++++++++++++++++++++++------------------------- calc_test.go | 323 +++++++++++++++------------- 2 files changed, 483 insertions(+), 423 deletions(-) diff --git a/calc.go b/calc.go index eed0f5d..cb7d2f8 100644 --- a/calc.go +++ b/calc.go @@ -455,7 +455,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error) Type: ArgString, }) } - + // call formula function to evaluate arg := callFuncByName(&formulaFuncs{}, strings.NewReplacer( "_xlfn", "", ".", "").Replace(opfStack.Peek().(efp.Token).TValue), []reflect.Value{reflect.ValueOf(argsStack.Peek().(*list.List))}) @@ -1573,14 +1573,14 @@ func (fn *formulaFuncs) CSCH(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "CSCH requires 1 numeric argument") } - val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + val := argsList.Front().Value.(formulaArg).ToNumber() + if val.Type == ArgError { + return val } - if val == 0 { + if val.Number == 0 { return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) } - return newNumberFormulaArg(1 / math.Sinh(val)) + return newNumberFormulaArg(1 / math.Sinh(val.Number)) } // DECIMAL function converts a text representation of a number in a specified @@ -1618,14 +1618,14 @@ func (fn *formulaFuncs) DEGREES(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "DEGREES requires 1 numeric argument") } - val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + val := argsList.Front().Value.(formulaArg).ToNumber() + if val.Type == ArgError { + return val } - if val == 0 { + if val.Number == 0 { return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) } - return newNumberFormulaArg(180.0 / math.Pi * val) + return newNumberFormulaArg(180.0 / math.Pi * val.Number) } // EVEN function rounds a supplied number away from zero (i.e. rounds a @@ -1638,12 +1638,12 @@ func (fn *formulaFuncs) EVEN(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "EVEN requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - sign := math.Signbit(number) - m, frac := math.Modf(number / 2) + sign := math.Signbit(number.Number) + m, frac := math.Modf(number.Number / 2) val := m * 2 if frac != 0 { if !sign { @@ -1664,11 +1664,11 @@ func (fn *formulaFuncs) EXP(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "EXP requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", math.Exp(number)))) + return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", math.Exp(number.Number)))) } // fact returns the factorial of a supplied number. @@ -1689,14 +1689,14 @@ func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "FACT requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number < 0 { + if number.Number < 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", fact(number)))) + return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", fact(number.Number)))) } // FACTDOUBLE function returns the double factorial of a supplied number. The @@ -1709,14 +1709,14 @@ func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) formulaArg { return newErrorFormulaArg(formulaErrorVALUE, "FACTDOUBLE requires 1 numeric argument") } val := 1.0 - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number < 0 { + if number.Number < 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - for i := math.Trunc(number); i > 1; i -= 2 { + for i := math.Trunc(number.Number); i > 1; i -= 2 { val *= i } return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val))) @@ -1731,27 +1731,25 @@ func (fn *formulaFuncs) FLOOR(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "FLOOR requires 2 numeric arguments") } - var number, significance float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + significance := argsList.Back().Value.(formulaArg).ToNumber() + if significance.Type == ArgError { + return significance } - if significance < 0 && number >= 0 { + if significance.Number < 0 && number.Number >= 0 { return newErrorFormulaArg(formulaErrorNUM, "invalid arguments to FLOOR") } - val := number - val, res := math.Modf(val / significance) + val := number.Number + val, res := math.Modf(val / significance.Number) if res != 0 { - if number < 0 && res < 0 { + if number.Number < 0 && res < 0 { val-- } } - return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val*significance))) + return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val*significance.Number))) } // FLOORMATH function rounds a supplied number down to a supplied multiple of @@ -1766,30 +1764,33 @@ func (fn *formulaFuncs) FLOORMATH(argsList *list.List) formulaArg { if argsList.Len() > 3 { return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH allows at most 3 arguments") } - number, significance, mode := 0.0, 1.0, 1.0 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + significance, mode := 1.0, 1.0 + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number < 0 { + if number.Number < 0 { significance = -1 } if argsList.Len() > 1 { - if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + s := argsList.Front().Next().Value.(formulaArg).ToNumber() + if s.Type == ArgError { + return s } + significance = s.Number } if argsList.Len() == 1 { - return newNumberFormulaArg(math.Floor(number)) + return newNumberFormulaArg(math.Floor(number.Number)) } if argsList.Len() > 2 { - if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + m := argsList.Back().Value.(formulaArg).ToNumber() + if m.Type == ArgError { + return m } + mode = m.Number } - val, res := math.Modf(number / significance) - if res != 0 && number < 0 && mode > 0 { + val, res := math.Modf(number.Number / significance) + if res != 0 && number.Number < 0 && mode > 0 { val-- } return newNumberFormulaArg(val * significance) @@ -1807,30 +1808,31 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) formulaArg { if argsList.Len() > 2 { return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE allows at most 2 arguments") } - var number, significance float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + var significance float64 + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number < 0 { + if number.Number < 0 { significance = -1 } if argsList.Len() == 1 { - return newNumberFormulaArg(math.Floor(number)) + return newNumberFormulaArg(math.Floor(number.Number)) } if argsList.Len() > 1 { - if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + s := argsList.Back().Value.(formulaArg).ToNumber() + if s.Type == ArgError { + return s } + significance = s.Number significance = math.Abs(significance) if significance == 0 { - return newStringFormulaArg("0") + return newNumberFormulaArg(significance) } } - val, res := math.Modf(number / significance) + val, res := math.Modf(number.Number / significance) if res != 0 { - if number < 0 { + if number.Number < 0 { val-- } } @@ -1871,12 +1873,19 @@ func (fn *formulaFuncs) GCD(argsList *list.List) formulaArg { err error ) for arg := argsList.Front(); arg != nil; arg = arg.Next() { - token := arg.Value.(formulaArg).String - if token == "" { - continue - } - if val, err = strconv.ParseFloat(token, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + token := arg.Value.(formulaArg) + switch token.Type { + case ArgString: + if token.String == "" { + continue + } + if val, err = strconv.ParseFloat(token.String, 64); err != nil { + return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + } + break + case ArgNumber: + val = token.Number + break } nums = append(nums, val) } @@ -1905,11 +1914,11 @@ func (fn *formulaFuncs) INT(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "INT requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - val, frac := math.Modf(number) + val, frac := math.Modf(number.Number) if frac < 0 { val-- } @@ -1929,29 +1938,31 @@ func (fn *formulaFuncs) ISOCEILING(argsList *list.List) formulaArg { if argsList.Len() > 2 { return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING allows at most 2 arguments") } - var number, significance float64 - var err error - if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + var significance float64 + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number < 0 { + if number.Number < 0 { significance = -1 } if argsList.Len() == 1 { - return newNumberFormulaArg(math.Ceil(number)) + return newNumberFormulaArg(math.Ceil(number.Number)) } if argsList.Len() > 1 { - if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + s := argsList.Back().Value.(formulaArg).ToNumber() + if s.Type == ArgError { + return s } + significance = s.Number significance = math.Abs(significance) if significance == 0 { - return newStringFormulaArg("0") + return newNumberFormulaArg(significance) } } - val, res := math.Modf(number / significance) + val, res := math.Modf(number.Number / significance) if res != 0 { - if number > 0 { + if number.Number > 0 { val++ } } @@ -1983,12 +1994,19 @@ func (fn *formulaFuncs) LCM(argsList *list.List) formulaArg { err error ) for arg := argsList.Front(); arg != nil; arg = arg.Next() { - token := arg.Value.(formulaArg).String - if token == "" { - continue - } - if val, err = strconv.ParseFloat(token, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + token := arg.Value.(formulaArg) + switch token.Type { + case ArgString: + if token.String == "" { + continue + } + if val, err = strconv.ParseFloat(token.String, 64); err != nil { + return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + } + break + case ArgNumber: + val = token.Number + break } nums = append(nums, val) } @@ -2017,11 +2035,11 @@ func (fn *formulaFuncs) LN(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "LN requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Log(number)) + return newNumberFormulaArg(math.Log(number.Number)) } // LOG function calculates the logarithm of a given number, to a supplied @@ -2036,18 +2054,19 @@ func (fn *formulaFuncs) LOG(argsList *list.List) formulaArg { if argsList.Len() > 2 { return newErrorFormulaArg(formulaErrorVALUE, "LOG allows at most 2 arguments") } - number, base := 0.0, 10.0 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + base := 10.0 + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } if argsList.Len() > 1 { - if base, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + b := argsList.Back().Value.(formulaArg).ToNumber() + if b.Type == ArgError { + return b } + base = b.Number } - if number == 0 { + if number.Number == 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV) } if base == 0 { @@ -2056,7 +2075,7 @@ func (fn *formulaFuncs) LOG(argsList *list.List) formulaArg { if base == 1 { return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) } - return newNumberFormulaArg(math.Log(number) / math.Log(base)) + return newNumberFormulaArg(math.Log(number.Number) / math.Log(base)) } // LOG10 function calculates the base 10 logarithm of a given number. The @@ -2068,11 +2087,11 @@ func (fn *formulaFuncs) LOG10(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "LOG10 requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Log10(number)) + return newNumberFormulaArg(math.Log10(number.Number)) } // minor function implement a minor of a matrix A is the determinant of some @@ -2153,24 +2172,22 @@ func (fn *formulaFuncs) MOD(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "MOD requires 2 numeric arguments") } - var number, divisor float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + divisor := argsList.Back().Value.(formulaArg).ToNumber() + if divisor.Type == ArgError { + return divisor } - if divisor == 0 { + if divisor.Number == 0 { return newErrorFormulaArg(formulaErrorDIV, "MOD divide by zero") } - trunc, rem := math.Modf(number / divisor) + trunc, rem := math.Modf(number.Number / divisor.Number) if rem < 0 { trunc-- } - return newNumberFormulaArg(number - divisor*trunc) + return newNumberFormulaArg(number.Number - divisor.Number*trunc) } // MROUND function rounds a supplied number up or down to the nearest multiple @@ -2182,28 +2199,26 @@ func (fn *formulaFuncs) MROUND(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "MROUND requires 2 numeric arguments") } - var number, multiple float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + n := argsList.Front().Value.(formulaArg).ToNumber() + if n.Type == ArgError { + return n } - multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + multiple := argsList.Back().Value.(formulaArg).ToNumber() + if multiple.Type == ArgError { + return multiple } - if multiple == 0 { + if multiple.Number == 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - if multiple < 0 && number > 0 || - multiple > 0 && number < 0 { + if multiple.Number < 0 && n.Number > 0 || + multiple.Number > 0 && n.Number < 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - number, res := math.Modf(number / multiple) + number, res := math.Modf(n.Number / multiple.Number) if math.Trunc(res+0.5) > 0 { number++ } - return newNumberFormulaArg(number * multiple) + return newNumberFormulaArg(number * multiple.Number) } // MULTINOMIAL function calculates the ratio of the factorial of a sum of @@ -2217,11 +2232,18 @@ func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) formulaArg { var err error for arg := argsList.Front(); arg != nil; arg = arg.Next() { token := arg.Value.(formulaArg) - if token.String == "" { - continue - } - if val, err = strconv.ParseFloat(token.String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + switch token.Type { + case ArgString: + if token.String == "" { + continue + } + if val, err = strconv.ParseFloat(token.String, 64); err != nil { + return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + } + break + case ArgNumber: + val = token.Number + break } num += val denom *= fact(val) @@ -2238,18 +2260,18 @@ func (fn *formulaFuncs) MUNIT(argsList *list.List) (result formulaArg) { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "MUNIT requires 1 numeric argument") } - dimension, err := strconv.Atoi(argsList.Front().Value.(formulaArg).String) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + dimension := argsList.Back().Value.(formulaArg).ToNumber() + if dimension.Type == ArgError { + return dimension } - matrix := make([][]formulaArg, 0, dimension) - for i := 0; i < dimension; i++ { - row := make([]formulaArg, dimension) - for j := 0; j < dimension; j++ { + matrix := make([][]formulaArg, 0, int(dimension.Number)) + for i := 0; i < int(dimension.Number); i++ { + row := make([]formulaArg, int(dimension.Number)) + for j := 0; j < int(dimension.Number); j++ { if i == j { - row[j] = newNumberFormulaArg(float64(1.0)) + row[j] = newNumberFormulaArg(1.0) } else { - row[j] = newNumberFormulaArg(float64(0.0)) + row[j] = newNumberFormulaArg(0.0) } } matrix = append(matrix, row) @@ -2267,15 +2289,15 @@ func (fn *formulaFuncs) ODD(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "ODD requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Back().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - if number == 0 { - return newStringFormulaArg("1") + if number.Number == 0 { + return newNumberFormulaArg(1) } - sign := math.Signbit(number) - m, frac := math.Modf((number - 1) / 2) + sign := math.Signbit(number.Number) + m, frac := math.Modf((number.Number - 1) / 2) val := m*2 + 1 if frac != 0 { if !sign { @@ -2308,23 +2330,21 @@ func (fn *formulaFuncs) POWER(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "POWER requires 2 numeric arguments") } - var x, y float64 - var err error - x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + x := argsList.Front().Value.(formulaArg).ToNumber() + if x.Type == ArgError { + return x } - y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + y := argsList.Back().Value.(formulaArg).ToNumber() + if y.Type == ArgError { + return y } - if x == 0 && y == 0 { + if x.Number == 0 && y.Number == 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - if x == 0 && y < 0 { + if x.Number == 0 && y.Number < 0 { return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) } - return newNumberFormulaArg(math.Pow(x, y)) + return newNumberFormulaArg(math.Pow(x.Number, y.Number)) } // PRODUCT function returns the product (multiplication) of a supplied set of @@ -2348,6 +2368,10 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) formulaArg { return newErrorFormulaArg(formulaErrorVALUE, err.Error()) } product = product * val + break + case ArgNumber: + product = product * token.Number + break case ArgMatrix: for _, row := range token.Matrix { for _, value := range row { @@ -2374,20 +2398,18 @@ func (fn *formulaFuncs) QUOTIENT(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "QUOTIENT requires 2 numeric arguments") } - var x, y float64 - var err error - x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + x := argsList.Front().Value.(formulaArg).ToNumber() + if x.Type == ArgError { + return x } - y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + y := argsList.Back().Value.(formulaArg).ToNumber() + if y.Type == ArgError { + return y } - if y == 0 { + if y.Number == 0 { return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) } - return newNumberFormulaArg(math.Trunc(x / y)) + return newNumberFormulaArg(math.Trunc(x.Number / y.Number)) } // RADIANS function converts radians into degrees. The syntax of the function is: @@ -2398,11 +2420,11 @@ func (fn *formulaFuncs) RADIANS(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "RADIANS requires 1 numeric argument") } - angle, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + angle := argsList.Front().Value.(formulaArg).ToNumber() + if angle.Type == ArgError { + return angle } - return newNumberFormulaArg(math.Pi / 180.0 * angle) + return newNumberFormulaArg(math.Pi / 180.0 * angle.Number) } // RAND function generates a random real number between 0 and 1. The syntax of @@ -2426,20 +2448,18 @@ func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "RANDBETWEEN requires 2 numeric arguments") } - var bottom, top int64 - var err error - bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).String, 10, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + bottom := argsList.Front().Value.(formulaArg).ToNumber() + if bottom.Type == ArgError { + return bottom } - top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).String, 10, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + top := argsList.Back().Value.(formulaArg).ToNumber() + if top.Type == ArgError { + return top } - if top < bottom { + if top.Number < bottom.Number { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - return newNumberFormulaArg(float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(top-bottom+1) + bottom)) + return newNumberFormulaArg(float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number-bottom.Number+1)) + int64(bottom.Number))) } // romanNumerals defined a numeral system that originated in ancient Rome and @@ -2469,17 +2489,17 @@ func (fn *formulaFuncs) ROMAN(argsList *list.List) formulaArg { if argsList.Len() > 2 { return newErrorFormulaArg(formulaErrorVALUE, "ROMAN allows at most 2 arguments") } - var number float64 var form int - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } if argsList.Len() > 1 { - if form, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + f := argsList.Back().Value.(formulaArg).ToNumber() + if f.Type == ArgError { + return f } + form = int(f.Number) if form < 0 { form = 0 } else if form > 4 { @@ -2497,7 +2517,7 @@ func (fn *formulaFuncs) ROMAN(argsList *list.List) formulaArg { case 4: decimalTable = romanTable[4] } - val := math.Trunc(number) + val := math.Trunc(number.Number) buf := bytes.Buffer{} for _, r := range decimalTable { for val >= r.n { @@ -2553,17 +2573,15 @@ func (fn *formulaFuncs) ROUND(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "ROUND requires 2 numeric arguments") } - var number, digits float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + digits := argsList.Back().Value.(formulaArg).ToNumber() + if digits.Type == ArgError { + return digits } - return newNumberFormulaArg(fn.round(number, digits, closest)) + return newNumberFormulaArg(fn.round(number.Number, digits.Number, closest)) } // ROUNDDOWN function rounds a supplied number down towards zero, to a @@ -2575,17 +2593,15 @@ func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "ROUNDDOWN requires 2 numeric arguments") } - var number, digits float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + digits := argsList.Back().Value.(formulaArg).ToNumber() + if digits.Type == ArgError { + return digits } - return newNumberFormulaArg(fn.round(number, digits, down)) + return newNumberFormulaArg(fn.round(number.Number, digits.Number, down)) } // ROUNDUP function rounds a supplied number up, away from zero, to a @@ -2597,17 +2613,15 @@ func (fn *formulaFuncs) ROUNDUP(argsList *list.List) formulaArg { if argsList.Len() != 2 { return newErrorFormulaArg(formulaErrorVALUE, "ROUNDUP requires 2 numeric arguments") } - var number, digits float64 - var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + digits := argsList.Back().Value.(formulaArg).ToNumber() + if digits.Type == ArgError { + return digits } - return newNumberFormulaArg(fn.round(number, digits, up)) + return newNumberFormulaArg(fn.round(number.Number, digits.Number, up)) } // SEC function calculates the secant of a given angle. The syntax of the @@ -2619,11 +2633,11 @@ func (fn *formulaFuncs) SEC(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SEC requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Cos(number)) + return newNumberFormulaArg(math.Cos(number.Number)) } // SECH function calculates the hyperbolic secant (sech) of a supplied angle. @@ -2635,11 +2649,11 @@ func (fn *formulaFuncs) SECH(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SECH requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(1 / math.Cosh(number)) + return newNumberFormulaArg(1 / math.Cosh(number.Number)) } // SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied @@ -2653,17 +2667,17 @@ func (fn *formulaFuncs) SIGN(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SIGN requires 1 numeric argument") } - val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + val := argsList.Front().Value.(formulaArg).ToNumber() + if val.Type == ArgError { + return val } - if val < 0 { - return newStringFormulaArg("-1") + if val.Number < 0 { + return newNumberFormulaArg(-1) } - if val > 0 { - return newStringFormulaArg("1") + if val.Number > 0 { + return newNumberFormulaArg(1) } - return newStringFormulaArg("0") + return newNumberFormulaArg(0) } // SIN function calculates the sine of a given angle. The syntax of the @@ -2675,11 +2689,11 @@ func (fn *formulaFuncs) SIN(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SIN requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Sin(number)) + return newNumberFormulaArg(math.Sin(number.Number)) } // SINH function calculates the hyperbolic sine (sinh) of a supplied number. @@ -2691,11 +2705,11 @@ func (fn *formulaFuncs) SINH(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SINH requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Sinh(number)) + return newNumberFormulaArg(math.Sinh(number.Number)) } // SQRT function calculates the positive square root of a supplied number. The @@ -2707,19 +2721,14 @@ func (fn *formulaFuncs) SQRT(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SQRT requires 1 numeric argument") } - var res float64 - var value = argsList.Front().Value.(formulaArg).String - if value == "" { - return newStringFormulaArg("0") + value := argsList.Front().Value.(formulaArg).ToNumber() + if value.Type == ArgError { + return value } - res, err := strconv.ParseFloat(value, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) - } - if res < 0 { + if value.Number < 0 { return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) } - return newNumberFormulaArg(math.Sqrt(res)) + return newNumberFormulaArg(math.Sqrt(value.Number)) } // SQRTPI function returns the square root of a supplied number multiplied by @@ -2731,11 +2740,11 @@ func (fn *formulaFuncs) SQRTPI(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "SQRTPI requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Sqrt(number * math.Pi)) + return newNumberFormulaArg(math.Sqrt(number.Number * math.Pi)) } // SUM function adds together a supplied set of numbers and returns the sum of @@ -2844,6 +2853,10 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) formulaArg { return newErrorFormulaArg(formulaErrorVALUE, err.Error()) } sq += val * val + break + case ArgNumber: + sq += token.Number + break case ArgMatrix: for _, row := range token.Matrix { for _, value := range row { @@ -2870,11 +2883,11 @@ func (fn *formulaFuncs) TAN(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "TAN requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Tan(number)) + return newNumberFormulaArg(math.Tan(number.Number)) } // TANH function calculates the hyperbolic tangent (tanh) of a supplied @@ -2886,11 +2899,11 @@ func (fn *formulaFuncs) TANH(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "TANH requires 1 numeric argument") } - number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } - return newNumberFormulaArg(math.Tanh(number)) + return newNumberFormulaArg(math.Tanh(number.Number)) } // TRUNC function truncates a supplied number to a specified number of decimal @@ -2902,29 +2915,31 @@ func (fn *formulaFuncs) TRUNC(argsList *list.List) formulaArg { if argsList.Len() == 0 { return newErrorFormulaArg(formulaErrorVALUE, "TRUNC requires at least 1 argument") } - var number, digits, adjust, rtrim float64 + var digits, adjust, rtrim float64 var err error - number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) - if err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + number := argsList.Front().Value.(formulaArg).ToNumber() + if number.Type == ArgError { + return number } if argsList.Len() > 1 { - if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { - return newErrorFormulaArg(formulaErrorVALUE, err.Error()) + d := argsList.Back().Value.(formulaArg).ToNumber() + if d.Type == ArgError { + return d } + digits = d.Number digits = math.Floor(digits) } adjust = math.Pow(10, digits) - x := int((math.Abs(number) - math.Abs(float64(int(number)))) * adjust) + x := int((math.Abs(number.Number) - math.Abs(float64(int(number.Number)))) * adjust) if x != 0 { if rtrim, err = strconv.ParseFloat(strings.TrimRight(strconv.Itoa(x), "0"), 64); err != nil { return newErrorFormulaArg(formulaErrorVALUE, err.Error()) } } if (digits > 0) && (rtrim < adjust/10) { - return newNumberFormulaArg(number) + return newNumberFormulaArg(number.Number) } - return newNumberFormulaArg(float64(int(number*adjust)) / adjust) + return newNumberFormulaArg(float64(int(number.Number*adjust)) / adjust) } // Statistical functions @@ -2976,6 +2991,10 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg { return newErrorFormulaArg(formulaErrorVALUE, err.Error()) } values = append(values, digits) + break + case ArgNumber: + values = append(values, arg.Number) + break case ArgMatrix: for _, row := range arg.Matrix { for _, value := range row { diff --git a/calc_test.go b/calc_test.go index d0b1c64..d3621c6 100644 --- a/calc_test.go +++ b/calc_test.go @@ -177,6 +177,7 @@ func TestCalcCellValue(t *testing.T) { "=_xlfn.CSC(_xlfn.CSC(1))": "1.077851840310882", // _xlfn.CSCH "=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047", + "=_xlfn.CSCH(_xlfn.CSCH(1))": "1.044510103955183", // _xlfn.DECIMAL `=_xlfn.DECIMAL("1100",2)`: "12", `=_xlfn.DECIMAL("186A0",16)`: "100000", @@ -184,8 +185,9 @@ func TestCalcCellValue(t *testing.T) { `=_xlfn.DECIMAL("70122",8)`: "28754", `=_xlfn.DECIMAL("0x70122",8)`: "28754", // DEGREES - "=DEGREES(1)": "57.29577951308232", - "=DEGREES(2.5)": "143.2394487827058", + "=DEGREES(1)": "57.29577951308232", + "=DEGREES(2.5)": "143.2394487827058", + "=DEGREES(DEGREES(1))": "3282.806350011744", // EVEN "=EVEN(23)": "24", "=EVEN(2.22)": "4", @@ -193,47 +195,54 @@ func TestCalcCellValue(t *testing.T) { "=EVEN(-0.3)": "-2", "=EVEN(-11)": "-12", "=EVEN(-4)": "-4", + "=EVEN((0))": "0", // EXP - "=EXP(100)": "2.6881171418161356E+43", - "=EXP(0.1)": "1.105170918075648", - "=EXP(0)": "1", - "=EXP(-5)": "0.006737946999085", + "=EXP(100)": "2.6881171418161356E+43", + "=EXP(0.1)": "1.105170918075648", + "=EXP(0)": "1", + "=EXP(-5)": "0.006737946999085", + "=EXP(EXP(0))": "2.718281828459045", // FACT - "=FACT(3)": "6", - "=FACT(6)": "720", - "=FACT(10)": "3.6288E+06", + "=FACT(3)": "6", + "=FACT(6)": "720", + "=FACT(10)": "3.6288E+06", + "=FACT(FACT(3))": "720", // FACTDOUBLE - "=FACTDOUBLE(5)": "15", - "=FACTDOUBLE(8)": "384", - "=FACTDOUBLE(13)": "135135", + "=FACTDOUBLE(5)": "15", + "=FACTDOUBLE(8)": "384", + "=FACTDOUBLE(13)": "135135", + "=FACTDOUBLE(FACTDOUBLE(1))": "1", // FLOOR - "=FLOOR(26.75,0.1)": "26.700000000000003", - "=FLOOR(26.75,0.5)": "26.5", - "=FLOOR(26.75,1)": "26", - "=FLOOR(26.75,10)": "20", - "=FLOOR(26.75,20)": "20", - "=FLOOR(-26.75,-0.1)": "-26.700000000000003", - "=FLOOR(-26.75,-1)": "-26", - "=FLOOR(-26.75,-5)": "-25", + "=FLOOR(26.75,0.1)": "26.700000000000003", + "=FLOOR(26.75,0.5)": "26.5", + "=FLOOR(26.75,1)": "26", + "=FLOOR(26.75,10)": "20", + "=FLOOR(26.75,20)": "20", + "=FLOOR(-26.75,-0.1)": "-26.700000000000003", + "=FLOOR(-26.75,-1)": "-26", + "=FLOOR(-26.75,-5)": "-25", + "=FLOOR(FLOOR(26.75,1),1)": "26", // _xlfn.FLOOR.MATH - "=_xlfn.FLOOR.MATH(58.55)": "58", - "=_xlfn.FLOOR.MATH(58.55,0.1)": "58.5", - "=_xlfn.FLOOR.MATH(58.55,5)": "55", - "=_xlfn.FLOOR.MATH(58.55,1,1)": "58", - "=_xlfn.FLOOR.MATH(-58.55,1)": "-59", - "=_xlfn.FLOOR.MATH(-58.55,1,-1)": "-58", - "=_xlfn.FLOOR.MATH(-58.55,1,1)": "-59", // should be -58 - "=_xlfn.FLOOR.MATH(-58.55,10)": "-60", + "=_xlfn.FLOOR.MATH(58.55)": "58", + "=_xlfn.FLOOR.MATH(58.55,0.1)": "58.5", + "=_xlfn.FLOOR.MATH(58.55,5)": "55", + "=_xlfn.FLOOR.MATH(58.55,1,1)": "58", + "=_xlfn.FLOOR.MATH(-58.55,1)": "-59", + "=_xlfn.FLOOR.MATH(-58.55,1,-1)": "-58", + "=_xlfn.FLOOR.MATH(-58.55,1,1)": "-59", // should be -58 + "=_xlfn.FLOOR.MATH(-58.55,10)": "-60", + "=_xlfn.FLOOR.MATH(_xlfn.FLOOR.MATH(1),10)": "0", // _xlfn.FLOOR.PRECISE - "=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.700000000000003", - "=_xlfn.FLOOR.PRECISE(26.75,0.5)": "26.5", - "=_xlfn.FLOOR.PRECISE(26.75,1)": "26", - "=_xlfn.FLOOR.PRECISE(26.75)": "26", - "=_xlfn.FLOOR.PRECISE(26.75,10)": "20", - "=_xlfn.FLOOR.PRECISE(26.75,0)": "0", - "=_xlfn.FLOOR.PRECISE(-26.75,1)": "-27", - "=_xlfn.FLOOR.PRECISE(-26.75,-1)": "-27", - "=_xlfn.FLOOR.PRECISE(-26.75,-5)": "-30", + "=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.700000000000003", + "=_xlfn.FLOOR.PRECISE(26.75,0.5)": "26.5", + "=_xlfn.FLOOR.PRECISE(26.75,1)": "26", + "=_xlfn.FLOOR.PRECISE(26.75)": "26", + "=_xlfn.FLOOR.PRECISE(26.75,10)": "20", + "=_xlfn.FLOOR.PRECISE(26.75,0)": "0", + "=_xlfn.FLOOR.PRECISE(-26.75,1)": "-27", + "=_xlfn.FLOOR.PRECISE(-26.75,-1)": "-27", + "=_xlfn.FLOOR.PRECISE(-26.75,-5)": "-30", + "=_xlfn.FLOOR.PRECISE(_xlfn.FLOOR.PRECISE(26.75),-5)": "25", // GCD "=GCD(0)": "0", `=GCD("",1)`: "1", @@ -242,61 +251,71 @@ func TestCalcCellValue(t *testing.T) { "=GCD(15,10,25)": "5", "=GCD(0,8,12)": "4", "=GCD(7,2)": "1", + "=GCD(1,GCD(1))": "1", // INT "=INT(100.9)": "100", "=INT(5.22)": "5", "=INT(5.99)": "5", "=INT(-6.1)": "-7", "=INT(-100.9)": "-101", + "=INT(INT(0))": "0", // ISO.CEILING - "=ISO.CEILING(22.25)": "23", - "=ISO.CEILING(22.25,1)": "23", - "=ISO.CEILING(22.25,0.1)": "22.3", - "=ISO.CEILING(22.25,10)": "30", - "=ISO.CEILING(-22.25,1)": "-22", - "=ISO.CEILING(-22.25,0.1)": "-22.200000000000003", - "=ISO.CEILING(-22.25,5)": "-20", - "=ISO.CEILING(-22.25,0)": "0", + "=ISO.CEILING(22.25)": "23", + "=ISO.CEILING(22.25,1)": "23", + "=ISO.CEILING(22.25,0.1)": "22.3", + "=ISO.CEILING(22.25,10)": "30", + "=ISO.CEILING(-22.25,1)": "-22", + "=ISO.CEILING(-22.25,0.1)": "-22.200000000000003", + "=ISO.CEILING(-22.25,5)": "-20", + "=ISO.CEILING(-22.25,0)": "0", + "=ISO.CEILING(1,ISO.CEILING(1,0))": "0", // LCM - "=LCM(1,5)": "5", - "=LCM(15,10,25)": "150", - "=LCM(1,8,12)": "24", - "=LCM(7,2)": "14", - "=LCM(7)": "7", - `=LCM("",1)`: "1", - `=LCM(0,0)`: "0", + "=LCM(1,5)": "5", + "=LCM(15,10,25)": "150", + "=LCM(1,8,12)": "24", + "=LCM(7,2)": "14", + "=LCM(7)": "7", + `=LCM("",1)`: "1", + `=LCM(0,0)`: "0", + `=LCM(0,LCM(0,0))`: "0", // LN - "=LN(1)": "0", - "=LN(100)": "4.605170185988092", - "=LN(0.5)": "-0.693147180559945", + "=LN(1)": "0", + "=LN(100)": "4.605170185988092", + "=LN(0.5)": "-0.693147180559945", + "=LN(LN(100))": "1.527179625807901", // LOG - "=LOG(64,2)": "6", - "=LOG(100)": "2", - "=LOG(4,0.5)": "-2", - "=LOG(500)": "2.698970004336019", + "=LOG(64,2)": "6", + "=LOG(100)": "2", + "=LOG(4,0.5)": "-2", + "=LOG(500)": "2.698970004336019", + "=LOG(LOG(100))": "0.301029995663981", // LOG10 - "=LOG10(100)": "2", - "=LOG10(1000)": "3", - "=LOG10(0.001)": "-3", - "=LOG10(25)": "1.397940008672038", + "=LOG10(100)": "2", + "=LOG10(1000)": "3", + "=LOG10(0.001)": "-3", + "=LOG10(25)": "1.397940008672038", + "=LOG10(LOG10(100))": "0.301029995663981", // MOD - "=MOD(6,4)": "2", - "=MOD(6,3)": "0", - "=MOD(6,2.5)": "1", - "=MOD(6,1.333)": "0.668", - "=MOD(-10.23,1)": "0.77", + "=MOD(6,4)": "2", + "=MOD(6,3)": "0", + "=MOD(6,2.5)": "1", + "=MOD(6,1.333)": "0.668", + "=MOD(-10.23,1)": "0.77", + "=MOD(MOD(1,1),1)": "0", // MROUND - "=MROUND(333.7,0.5)": "333.5", - "=MROUND(333.8,1)": "334", - "=MROUND(333.3,2)": "334", - "=MROUND(555.3,400)": "400", - "=MROUND(555,1000)": "1000", - "=MROUND(-555.7,-1)": "-556", - "=MROUND(-555.4,-1)": "-555", - "=MROUND(-1555,-1000)": "-2000", + "=MROUND(333.7,0.5)": "333.5", + "=MROUND(333.8,1)": "334", + "=MROUND(333.3,2)": "334", + "=MROUND(555.3,400)": "400", + "=MROUND(555,1000)": "1000", + "=MROUND(-555.7,-1)": "-556", + "=MROUND(-555.4,-1)": "-555", + "=MROUND(-1555,-1000)": "-2000", + "=MROUND(MROUND(1,1),1)": "1", // MULTINOMIAL - "=MULTINOMIAL(3,1,2,5)": "27720", - `=MULTINOMIAL("",3,1,2,5)`: "27720", + "=MULTINOMIAL(3,1,2,5)": "27720", + `=MULTINOMIAL("",3,1,2,5)`: "27720", + "=MULTINOMIAL(MULTINOMIAL(1))": "1", // _xlfn.MUNIT "=_xlfn.MUNIT(4)": "", // ODD @@ -307,81 +326,96 @@ func TestCalcCellValue(t *testing.T) { "=ODD(-1.3)": "-3", "=ODD(-10)": "-11", "=ODD(-3)": "-3", + "=ODD(ODD(1))": "1", // PI "=PI()": "3.141592653589793", // POWER - "=POWER(4,2)": "16", + "=POWER(4,2)": "16", + "=POWER(4,POWER(1,1))": "4", // PRODUCT - "=PRODUCT(3,6)": "18", - `=PRODUCT("",3,6)`: "18", + "=PRODUCT(3,6)": "18", + `=PRODUCT("",3,6)`: "18", + `=PRODUCT(PRODUCT(1),3,6)`: "18", // QUOTIENT - "=QUOTIENT(5,2)": "2", - "=QUOTIENT(4.5,3.1)": "1", - "=QUOTIENT(-10,3)": "-3", + "=QUOTIENT(5,2)": "2", + "=QUOTIENT(4.5,3.1)": "1", + "=QUOTIENT(-10,3)": "-3", + "=QUOTIENT(QUOTIENT(1,2),3)": "0", // RADIANS - "=RADIANS(50)": "0.872664625997165", - "=RADIANS(-180)": "-3.141592653589793", - "=RADIANS(180)": "3.141592653589793", - "=RADIANS(360)": "6.283185307179586", + "=RADIANS(50)": "0.872664625997165", + "=RADIANS(-180)": "-3.141592653589793", + "=RADIANS(180)": "3.141592653589793", + "=RADIANS(360)": "6.283185307179586", + "=RADIANS(RADIANS(360))": "0.109662271123215", // ROMAN - "=ROMAN(499,0)": "CDXCIX", - "=ROMAN(1999,0)": "MCMXCIX", - "=ROMAN(1999,1)": "MLMVLIV", - "=ROMAN(1999,2)": "MXMIX", - "=ROMAN(1999,3)": "MVMIV", - "=ROMAN(1999,4)": "MIM", - "=ROMAN(1999,-1)": "MCMXCIX", - "=ROMAN(1999,5)": "MIM", + "=ROMAN(499,0)": "CDXCIX", + "=ROMAN(1999,0)": "MCMXCIX", + "=ROMAN(1999,1)": "MLMVLIV", + "=ROMAN(1999,2)": "MXMIX", + "=ROMAN(1999,3)": "MVMIV", + "=ROMAN(1999,4)": "MIM", + "=ROMAN(1999,-1)": "MCMXCIX", + "=ROMAN(1999,5)": "MIM", + "=ROMAN(1999,ODD(1))": "MLMVLIV", // ROUND - "=ROUND(100.319,1)": "100.30000000000001", - "=ROUND(5.28,1)": "5.300000000000001", - "=ROUND(5.9999,3)": "6.000000000000002", - "=ROUND(99.5,0)": "100", - "=ROUND(-6.3,0)": "-6", - "=ROUND(-100.5,0)": "-101", - "=ROUND(-22.45,1)": "-22.5", - "=ROUND(999,-1)": "1000", - "=ROUND(991,-1)": "990", + "=ROUND(100.319,1)": "100.30000000000001", + "=ROUND(5.28,1)": "5.300000000000001", + "=ROUND(5.9999,3)": "6.000000000000002", + "=ROUND(99.5,0)": "100", + "=ROUND(-6.3,0)": "-6", + "=ROUND(-100.5,0)": "-101", + "=ROUND(-22.45,1)": "-22.5", + "=ROUND(999,-1)": "1000", + "=ROUND(991,-1)": "990", + "=ROUND(ROUND(100,1),-1)": "100", // ROUNDDOWN - "=ROUNDDOWN(99.999,1)": "99.9", - "=ROUNDDOWN(99.999,2)": "99.99000000000002", - "=ROUNDDOWN(99.999,0)": "99", - "=ROUNDDOWN(99.999,-1)": "90", - "=ROUNDDOWN(-99.999,2)": "-99.99000000000002", - "=ROUNDDOWN(-99.999,-1)": "-90", + "=ROUNDDOWN(99.999,1)": "99.9", + "=ROUNDDOWN(99.999,2)": "99.99000000000002", + "=ROUNDDOWN(99.999,0)": "99", + "=ROUNDDOWN(99.999,-1)": "90", + "=ROUNDDOWN(-99.999,2)": "-99.99000000000002", + "=ROUNDDOWN(-99.999,-1)": "-90", + "=ROUNDDOWN(ROUNDDOWN(100,1),-1)": "100", // ROUNDUP` - "=ROUNDUP(11.111,1)": "11.200000000000001", - "=ROUNDUP(11.111,2)": "11.120000000000003", - "=ROUNDUP(11.111,0)": "12", - "=ROUNDUP(11.111,-1)": "20", - "=ROUNDUP(-11.111,2)": "-11.120000000000003", - "=ROUNDUP(-11.111,-1)": "-20", + "=ROUNDUP(11.111,1)": "11.200000000000001", + "=ROUNDUP(11.111,2)": "11.120000000000003", + "=ROUNDUP(11.111,0)": "12", + "=ROUNDUP(11.111,-1)": "20", + "=ROUNDUP(-11.111,2)": "-11.120000000000003", + "=ROUNDUP(-11.111,-1)": "-20", + "=ROUNDUP(ROUNDUP(100,1),-1)": "100", // SEC "=_xlfn.SEC(-3.14159265358979)": "-1", "=_xlfn.SEC(0)": "1", + "=_xlfn.SEC(_xlfn.SEC(0))": "0.54030230586814", // SECH "=_xlfn.SECH(-3.14159265358979)": "0.086266738334055", "=_xlfn.SECH(0)": "1", + "=_xlfn.SECH(_xlfn.SECH(0))": "0.648054273663886", // SIGN "=SIGN(9.5)": "1", "=SIGN(-9.5)": "-1", "=SIGN(0)": "0", "=SIGN(0.00000001)": "1", "=SIGN(6-7)": "-1", + "=SIGN(SIGN(-1))": "-1", // SIN "=SIN(0.785398163)": "0.707106780905509", + "=SIN(SIN(1))": "0.745624141665558", // SINH - "=SINH(0)": "0", - "=SINH(0.5)": "0.521095305493747", - "=SINH(-2)": "-3.626860407847019", + "=SINH(0)": "0", + "=SINH(0.5)": "0.521095305493747", + "=SINH(-2)": "-3.626860407847019", + "=SINH(SINH(0))": "0", // SQRT - "=SQRT(4)": "2", - `=SQRT("")`: "0", + "=SQRT(4)": "2", + "=SQRT(SQRT(16))": "2", // SQRTPI - "=SQRTPI(5)": "3.963327297606011", - "=SQRTPI(0.2)": "0.792665459521202", - "=SQRTPI(100)": "17.72453850905516", - "=SQRTPI(0)": "0", + "=SQRTPI(5)": "3.963327297606011", + "=SQRTPI(0.2)": "0.792665459521202", + "=SQRTPI(100)": "17.72453850905516", + "=SQRTPI(0)": "0", + "=SQRTPI(SQRTPI(0))": "0", // SUM "=SUM(1,2)": "3", `=SUM("",1,2)`: "3", @@ -415,27 +449,33 @@ func TestCalcCellValue(t *testing.T) { "=SUMSQ(A1:A4)": "14", "=SUMSQ(A1,B1,A2,B2,6)": "82", `=SUMSQ("",A1,B1,A2,B2,6)`: "82", + `=SUMSQ(1,SUMSQ(1))`: "2", // TAN "=TAN(1.047197551)": "1.732050806782486", "=TAN(0)": "0", + "=TAN(TAN(0))": "0", // TANH - "=TANH(0)": "0", - "=TANH(0.5)": "0.46211715726001", - "=TANH(-2)": "-0.964027580075817", + "=TANH(0)": "0", + "=TANH(0.5)": "0.46211715726001", + "=TANH(-2)": "-0.964027580075817", + "=TANH(TANH(0))": "0", // TRUNC - "=TRUNC(99.999,1)": "99.9", - "=TRUNC(99.999,2)": "99.99", - "=TRUNC(99.999)": "99", - "=TRUNC(99.999,-1)": "90", - "=TRUNC(-99.999,2)": "-99.99", - "=TRUNC(-99.999,-1)": "-90", + "=TRUNC(99.999,1)": "99.9", + "=TRUNC(99.999,2)": "99.99", + "=TRUNC(99.999)": "99", + "=TRUNC(99.999,-1)": "90", + "=TRUNC(-99.999,2)": "-99.99", + "=TRUNC(-99.999,-1)": "-90", + "=TRUNC(TRUNC(1),-1)": "0", // Statistical Functions // COUNTA `=COUNTA()`: "0", `=COUNTA(A1:A5,B2:B5,"text",1,2)`: "8", + `=COUNTA(COUNTA(1))`: "1", // MEDIAN - "=MEDIAN(A1:A5,12)": "2", - "=MEDIAN(A1:A5)": "1.5", + "=MEDIAN(A1:A5,12)": "2", + "=MEDIAN(A1:A5)": "1.5", + "=MEDIAN(A1:A5,MEDIAN(A1:A5,12))": "2", // Information Functions // ISBLANK "=ISBLANK(A1)": "FALSE", @@ -706,8 +746,8 @@ func TestCalcCellValue(t *testing.T) { // MULTINOMIAL `=MULTINOMIAL("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", // _xlfn.MUNIT - "=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently - `=_xlfn.MUNIT("X")`: "strconv.Atoi: parsing \"X\": invalid syntax", // not support currently + "=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently + `=_xlfn.MUNIT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", // not support currently // ODD "=ODD()": "ODD requires 1 numeric argument", `=ODD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", @@ -732,8 +772,8 @@ func TestCalcCellValue(t *testing.T) { // RAND "=RAND(1)": "RAND accepts no arguments", // RANDBETWEEN - `=RANDBETWEEN("X",1)`: "strconv.ParseInt: parsing \"X\": invalid syntax", - `=RANDBETWEEN(1,"X")`: "strconv.ParseInt: parsing \"X\": invalid syntax", + `=RANDBETWEEN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax", + `=RANDBETWEEN(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", "=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments", "=RANDBETWEEN(2,1)": "#NUM!", // ROMAN @@ -770,6 +810,7 @@ func TestCalcCellValue(t *testing.T) { `=SINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", // SQRT "=SQRT()": "SQRT requires 1 numeric argument", + `=SQRT("")`: "strconv.ParseFloat: parsing \"\": invalid syntax", `=SQRT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", "=SQRT(-1)": "#NUM!", // SQRTPI