update formula functions test

This commit is contained in:
xuri 2021-02-01 00:07:51 +08:00
parent 4ac32278ff
commit db7b4ee362
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
2 changed files with 483 additions and 423 deletions

561
calc.go
View File

@ -455,7 +455,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
Type: ArgString, Type: ArgString,
}) })
} }
// call formula function to evaluate
arg := callFuncByName(&formulaFuncs{}, strings.NewReplacer( arg := callFuncByName(&formulaFuncs{}, strings.NewReplacer(
"_xlfn", "", ".", "").Replace(opfStack.Peek().(efp.Token).TValue), "_xlfn", "", ".", "").Replace(opfStack.Peek().(efp.Token).TValue),
[]reflect.Value{reflect.ValueOf(argsStack.Peek().(*list.List))}) []reflect.Value{reflect.ValueOf(argsStack.Peek().(*list.List))})
@ -1573,14 +1573,14 @@ func (fn *formulaFuncs) CSCH(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "CSCH requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "CSCH requires 1 numeric argument")
} }
val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) val := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if val.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return val
} }
if val == 0 { if val.Number == 0 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "DEGREES requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "DEGREES requires 1 numeric argument")
} }
val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) val := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if val.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return val
} }
if val == 0 { if val.Number == 0 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "EVEN requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "EVEN requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
sign := math.Signbit(number) sign := math.Signbit(number.Number)
m, frac := math.Modf(number / 2) m, frac := math.Modf(number.Number / 2)
val := m * 2 val := m * 2
if frac != 0 { if frac != 0 {
if !sign { if !sign {
@ -1664,11 +1664,11 @@ func (fn *formulaFuncs) EXP(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "EXP requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "EXP requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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. // fact returns the factorial of a supplied number.
@ -1689,14 +1689,14 @@ func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "FACT requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "FACT requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
if number < 0 { if number.Number < 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) 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 // 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") return newErrorFormulaArg(formulaErrorVALUE, "FACTDOUBLE requires 1 numeric argument")
} }
val := 1.0 val := 1.0
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
if number < 0 { if number.Number < 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) 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 val *= i
} }
return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val))) return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val)))
@ -1731,27 +1731,25 @@ func (fn *formulaFuncs) FLOOR(argsList *list.List) formulaArg {
if argsList.Len() != 2 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "FLOOR requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "FLOOR requires 2 numeric arguments")
} }
var number, significance float64 number := argsList.Front().Value.(formulaArg).ToNumber()
var err error if number.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return number
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) significance := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if significance.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return significance
} }
if significance < 0 && number >= 0 { if significance.Number < 0 && number.Number >= 0 {
return newErrorFormulaArg(formulaErrorNUM, "invalid arguments to FLOOR") return newErrorFormulaArg(formulaErrorNUM, "invalid arguments to FLOOR")
} }
val := number val := number.Number
val, res := math.Modf(val / significance) val, res := math.Modf(val / significance.Number)
if res != 0 { if res != 0 {
if number < 0 && res < 0 { if number.Number < 0 && res < 0 {
val-- 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 // 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 { if argsList.Len() > 3 {
return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH allows at most 3 arguments") return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH allows at most 3 arguments")
} }
number, significance, mode := 0.0, 1.0, 1.0 significance, mode := 1.0, 1.0
var err error number := argsList.Front().Value.(formulaArg).ToNumber()
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) if number.Type == ArgError {
if err != nil { return number
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
if number < 0 { if number.Number < 0 {
significance = -1 significance = -1
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).String, 64); err != nil { s := argsList.Front().Next().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if s.Type == ArgError {
return s
} }
significance = s.Number
} }
if argsList.Len() == 1 { if argsList.Len() == 1 {
return newNumberFormulaArg(math.Floor(number)) return newNumberFormulaArg(math.Floor(number.Number))
} }
if argsList.Len() > 2 { if argsList.Len() > 2 {
if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { m := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if m.Type == ArgError {
return m
} }
mode = m.Number
} }
val, res := math.Modf(number / significance) val, res := math.Modf(number.Number / significance)
if res != 0 && number < 0 && mode > 0 { if res != 0 && number.Number < 0 && mode > 0 {
val-- val--
} }
return newNumberFormulaArg(val * significance) return newNumberFormulaArg(val * significance)
@ -1807,30 +1808,31 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) formulaArg {
if argsList.Len() > 2 { if argsList.Len() > 2 {
return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE allows at most 2 arguments") return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE allows at most 2 arguments")
} }
var number, significance float64 var significance float64
var err error number := argsList.Front().Value.(formulaArg).ToNumber()
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) if number.Type == ArgError {
if err != nil { return number
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
if number < 0 { if number.Number < 0 {
significance = -1 significance = -1
} }
if argsList.Len() == 1 { if argsList.Len() == 1 {
return newNumberFormulaArg(math.Floor(number)) return newNumberFormulaArg(math.Floor(number.Number))
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { s := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if s.Type == ArgError {
return s
} }
significance = s.Number
significance = math.Abs(significance) significance = math.Abs(significance)
if significance == 0 { 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 res != 0 {
if number < 0 { if number.Number < 0 {
val-- val--
} }
} }
@ -1871,13 +1873,20 @@ func (fn *formulaFuncs) GCD(argsList *list.List) formulaArg {
err error err error
) )
for arg := argsList.Front(); arg != nil; arg = arg.Next() { for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg).String token := arg.Value.(formulaArg)
if token == "" { switch token.Type {
case ArgString:
if token.String == "" {
continue continue
} }
if val, err = strconv.ParseFloat(token, 64); err != nil { if val, err = strconv.ParseFloat(token.String, 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
break
case ArgNumber:
val = token.Number
break
}
nums = append(nums, val) nums = append(nums, val)
} }
if nums[0] < 0 { if nums[0] < 0 {
@ -1905,11 +1914,11 @@ func (fn *formulaFuncs) INT(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "INT requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "INT requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
val, frac := math.Modf(number) val, frac := math.Modf(number.Number)
if frac < 0 { if frac < 0 {
val-- val--
} }
@ -1929,29 +1938,31 @@ func (fn *formulaFuncs) ISOCEILING(argsList *list.List) formulaArg {
if argsList.Len() > 2 { if argsList.Len() > 2 {
return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING allows at most 2 arguments") return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING allows at most 2 arguments")
} }
var number, significance float64 var significance float64
var err error number := argsList.Front().Value.(formulaArg).ToNumber()
if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
if number < 0 { if number.Number < 0 {
significance = -1 significance = -1
} }
if argsList.Len() == 1 { if argsList.Len() == 1 {
return newNumberFormulaArg(math.Ceil(number)) return newNumberFormulaArg(math.Ceil(number.Number))
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { s := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if s.Type == ArgError {
return s
} }
significance = s.Number
significance = math.Abs(significance) significance = math.Abs(significance)
if significance == 0 { 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 res != 0 {
if number > 0 { if number.Number > 0 {
val++ val++
} }
} }
@ -1983,13 +1994,20 @@ func (fn *formulaFuncs) LCM(argsList *list.List) formulaArg {
err error err error
) )
for arg := argsList.Front(); arg != nil; arg = arg.Next() { for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg).String token := arg.Value.(formulaArg)
if token == "" { switch token.Type {
case ArgString:
if token.String == "" {
continue continue
} }
if val, err = strconv.ParseFloat(token, 64); err != nil { if val, err = strconv.ParseFloat(token.String, 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
break
case ArgNumber:
val = token.Number
break
}
nums = append(nums, val) nums = append(nums, val)
} }
if nums[0] < 0 { if nums[0] < 0 {
@ -2017,11 +2035,11 @@ func (fn *formulaFuncs) LN(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "LN requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "LN requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() > 2 {
return newErrorFormulaArg(formulaErrorVALUE, "LOG allows at most 2 arguments") return newErrorFormulaArg(formulaErrorVALUE, "LOG allows at most 2 arguments")
} }
number, base := 0.0, 10.0 base := 10.0
var err error number := argsList.Front().Value.(formulaArg).ToNumber()
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) if number.Type == ArgError {
if err != nil { return number
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if base, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { b := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if b.Type == ArgError {
return b
} }
base = b.Number
} }
if number == 0 { if number.Number == 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV) return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV)
} }
if base == 0 { if base == 0 {
@ -2056,7 +2075,7 @@ func (fn *formulaFuncs) LOG(argsList *list.List) formulaArg {
if base == 1 { if base == 1 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "LOG10 requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "LOG10 requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "MOD requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "MOD requires 2 numeric arguments")
} }
var number, divisor float64 number := argsList.Front().Value.(formulaArg).ToNumber()
var err error if number.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return number
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) divisor := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if divisor.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return divisor
} }
if divisor == 0 { if divisor.Number == 0 {
return newErrorFormulaArg(formulaErrorDIV, "MOD divide by zero") return newErrorFormulaArg(formulaErrorDIV, "MOD divide by zero")
} }
trunc, rem := math.Modf(number / divisor) trunc, rem := math.Modf(number.Number / divisor.Number)
if rem < 0 { if rem < 0 {
trunc-- 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 // 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 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "MROUND requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "MROUND requires 2 numeric arguments")
} }
var number, multiple float64 n := argsList.Front().Value.(formulaArg).ToNumber()
var err error if n.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return n
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) multiple := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if multiple.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return multiple
} }
if multiple == 0 { if multiple.Number == 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
} }
if multiple < 0 && number > 0 || if multiple.Number < 0 && n.Number > 0 ||
multiple > 0 && number < 0 { multiple.Number > 0 && n.Number < 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) 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 { if math.Trunc(res+0.5) > 0 {
number++ number++
} }
return newNumberFormulaArg(number * multiple) return newNumberFormulaArg(number * multiple.Number)
} }
// MULTINOMIAL function calculates the ratio of the factorial of a sum of // MULTINOMIAL function calculates the ratio of the factorial of a sum of
@ -2217,12 +2232,19 @@ func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) formulaArg {
var err error var err error
for arg := argsList.Front(); arg != nil; arg = arg.Next() { for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg) token := arg.Value.(formulaArg)
switch token.Type {
case ArgString:
if token.String == "" { if token.String == "" {
continue continue
} }
if val, err = strconv.ParseFloat(token.String, 64); err != nil { if val, err = strconv.ParseFloat(token.String, 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
break
case ArgNumber:
val = token.Number
break
}
num += val num += val
denom *= fact(val) denom *= fact(val)
} }
@ -2238,18 +2260,18 @@ func (fn *formulaFuncs) MUNIT(argsList *list.List) (result formulaArg) {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "MUNIT requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "MUNIT requires 1 numeric argument")
} }
dimension, err := strconv.Atoi(argsList.Front().Value.(formulaArg).String) dimension := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if dimension.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return dimension
} }
matrix := make([][]formulaArg, 0, dimension) matrix := make([][]formulaArg, 0, int(dimension.Number))
for i := 0; i < dimension; i++ { for i := 0; i < int(dimension.Number); i++ {
row := make([]formulaArg, dimension) row := make([]formulaArg, int(dimension.Number))
for j := 0; j < dimension; j++ { for j := 0; j < int(dimension.Number); j++ {
if i == j { if i == j {
row[j] = newNumberFormulaArg(float64(1.0)) row[j] = newNumberFormulaArg(1.0)
} else { } else {
row[j] = newNumberFormulaArg(float64(0.0)) row[j] = newNumberFormulaArg(0.0)
} }
} }
matrix = append(matrix, row) matrix = append(matrix, row)
@ -2267,15 +2289,15 @@ func (fn *formulaFuncs) ODD(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "ODD requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "ODD requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
if number == 0 { if number.Number == 0 {
return newStringFormulaArg("1") return newNumberFormulaArg(1)
} }
sign := math.Signbit(number) sign := math.Signbit(number.Number)
m, frac := math.Modf((number - 1) / 2) m, frac := math.Modf((number.Number - 1) / 2)
val := m*2 + 1 val := m*2 + 1
if frac != 0 { if frac != 0 {
if !sign { if !sign {
@ -2308,23 +2330,21 @@ func (fn *formulaFuncs) POWER(argsList *list.List) formulaArg {
if argsList.Len() != 2 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "POWER requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "POWER requires 2 numeric arguments")
} }
var x, y float64 x := argsList.Front().Value.(formulaArg).ToNumber()
var err error if x.Type == ArgError {
x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return x
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) y := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if y.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return y
} }
if x == 0 && y == 0 { if x.Number == 0 && y.Number == 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
} }
if x == 0 && y < 0 { if x.Number == 0 && y.Number < 0 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) 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 // 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()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
product = product * val product = product * val
break
case ArgNumber:
product = product * token.Number
break
case ArgMatrix: case ArgMatrix:
for _, row := range token.Matrix { for _, row := range token.Matrix {
for _, value := range row { for _, value := range row {
@ -2374,20 +2398,18 @@ func (fn *formulaFuncs) QUOTIENT(argsList *list.List) formulaArg {
if argsList.Len() != 2 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "QUOTIENT requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "QUOTIENT requires 2 numeric arguments")
} }
var x, y float64 x := argsList.Front().Value.(formulaArg).ToNumber()
var err error if x.Type == ArgError {
x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return x
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) y := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if y.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return y
} }
if y == 0 { if y.Number == 0 {
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV) 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: // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "RADIANS requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "RADIANS requires 1 numeric argument")
} }
angle, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) angle := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if angle.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "RANDBETWEEN requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "RANDBETWEEN requires 2 numeric arguments")
} }
var bottom, top int64 bottom := argsList.Front().Value.(formulaArg).ToNumber()
var err error if bottom.Type == ArgError {
bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).String, 10, 64) return bottom
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).String, 10, 64) top := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if top.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return top
} }
if top < bottom { if top.Number < bottom.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) 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 // 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 { if argsList.Len() > 2 {
return newErrorFormulaArg(formulaErrorVALUE, "ROMAN allows at most 2 arguments") return newErrorFormulaArg(formulaErrorVALUE, "ROMAN allows at most 2 arguments")
} }
var number float64
var form int var form int
var err error number := argsList.Front().Value.(formulaArg).ToNumber()
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) if number.Type == ArgError {
if err != nil { return number
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if form, err = strconv.Atoi(argsList.Back().Value.(formulaArg).String); err != nil { f := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if f.Type == ArgError {
return f
} }
form = int(f.Number)
if form < 0 { if form < 0 {
form = 0 form = 0
} else if form > 4 { } else if form > 4 {
@ -2497,7 +2517,7 @@ func (fn *formulaFuncs) ROMAN(argsList *list.List) formulaArg {
case 4: case 4:
decimalTable = romanTable[4] decimalTable = romanTable[4]
} }
val := math.Trunc(number) val := math.Trunc(number.Number)
buf := bytes.Buffer{} buf := bytes.Buffer{}
for _, r := range decimalTable { for _, r := range decimalTable {
for val >= r.n { for val >= r.n {
@ -2553,17 +2573,15 @@ func (fn *formulaFuncs) ROUND(argsList *list.List) formulaArg {
if argsList.Len() != 2 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "ROUND requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "ROUND requires 2 numeric arguments")
} }
var number, digits float64 number := argsList.Front().Value.(formulaArg).ToNumber()
var err error if number.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return number
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) digits := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if digits.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "ROUNDDOWN requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "ROUNDDOWN requires 2 numeric arguments")
} }
var number, digits float64 number := argsList.Front().Value.(formulaArg).ToNumber()
var err error if number.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return number
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) digits := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if digits.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 2 {
return newErrorFormulaArg(formulaErrorVALUE, "ROUNDUP requires 2 numeric arguments") return newErrorFormulaArg(formulaErrorVALUE, "ROUNDUP requires 2 numeric arguments")
} }
var number, digits float64 number := argsList.Front().Value.(formulaArg).ToNumber()
var err error if number.Type == ArgError {
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) return number
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64) digits := argsList.Back().Value.(formulaArg).ToNumber()
if err != nil { if digits.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SEC requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SEC requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
return newNumberFormulaArg(math.Cos(number)) return newNumberFormulaArg(math.Cos(number.Number))
} }
// SECH function calculates the hyperbolic secant (sech) of a supplied angle. // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SECH requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SECH requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SIGN requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SIGN requires 1 numeric argument")
} }
val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) val := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if val.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return val
} }
if val < 0 { if val.Number < 0 {
return newStringFormulaArg("-1") return newNumberFormulaArg(-1)
} }
if val > 0 { if val.Number > 0 {
return newStringFormulaArg("1") return newNumberFormulaArg(1)
} }
return newStringFormulaArg("0") return newNumberFormulaArg(0)
} }
// SIN function calculates the sine of a given angle. The syntax of the // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SIN requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SIN requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
return newNumberFormulaArg(math.Sin(number)) return newNumberFormulaArg(math.Sin(number.Number))
} }
// SINH function calculates the hyperbolic sine (sinh) of a supplied 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SINH requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SINH requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SQRT requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SQRT requires 1 numeric argument")
} }
var res float64 value := argsList.Front().Value.(formulaArg).ToNumber()
var value = argsList.Front().Value.(formulaArg).String if value.Type == ArgError {
if value == "" { return value
return newStringFormulaArg("0")
} }
res, err := strconv.ParseFloat(value, 64) if value.Number < 0 {
if err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
if res < 0 {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) 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 // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "SQRTPI requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "SQRTPI requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
sq += val * val sq += val * val
break
case ArgNumber:
sq += token.Number
break
case ArgMatrix: case ArgMatrix:
for _, row := range token.Matrix { for _, row := range token.Matrix {
for _, value := range row { for _, value := range row {
@ -2870,11 +2883,11 @@ func (fn *formulaFuncs) TAN(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "TAN requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "TAN requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
return newNumberFormulaArg(math.Tan(number)) return newNumberFormulaArg(math.Tan(number.Number))
} }
// TANH function calculates the hyperbolic tangent (tanh) of a supplied // 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 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "TANH requires 1 numeric argument") return newErrorFormulaArg(formulaErrorVALUE, "TANH requires 1 numeric argument")
} }
number, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) 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 // 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 { if argsList.Len() == 0 {
return newErrorFormulaArg(formulaErrorVALUE, "TRUNC requires at least 1 argument") return newErrorFormulaArg(formulaErrorVALUE, "TRUNC requires at least 1 argument")
} }
var number, digits, adjust, rtrim float64 var digits, adjust, rtrim float64
var err error var err error
number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64) number := argsList.Front().Value.(formulaArg).ToNumber()
if err != nil { if number.Type == ArgError {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return number
} }
if argsList.Len() > 1 { if argsList.Len() > 1 {
if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil { d := argsList.Back().Value.(formulaArg).ToNumber()
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) if d.Type == ArgError {
return d
} }
digits = d.Number
digits = math.Floor(digits) digits = math.Floor(digits)
} }
adjust = math.Pow(10, 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 x != 0 {
if rtrim, err = strconv.ParseFloat(strings.TrimRight(strconv.Itoa(x), "0"), 64); err != nil { if rtrim, err = strconv.ParseFloat(strings.TrimRight(strconv.Itoa(x), "0"), 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
} }
if (digits > 0) && (rtrim < adjust/10) { 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 // Statistical functions
@ -2976,6 +2991,10 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, err.Error()) return newErrorFormulaArg(formulaErrorVALUE, err.Error())
} }
values = append(values, digits) values = append(values, digits)
break
case ArgNumber:
values = append(values, arg.Number)
break
case ArgMatrix: case ArgMatrix:
for _, row := range arg.Matrix { for _, row := range arg.Matrix {
for _, value := range row { for _, value := range row {

View File

@ -177,6 +177,7 @@ func TestCalcCellValue(t *testing.T) {
"=_xlfn.CSC(_xlfn.CSC(1))": "1.077851840310882", "=_xlfn.CSC(_xlfn.CSC(1))": "1.077851840310882",
// _xlfn.CSCH // _xlfn.CSCH
"=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047", "=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047",
"=_xlfn.CSCH(_xlfn.CSCH(1))": "1.044510103955183",
// _xlfn.DECIMAL // _xlfn.DECIMAL
`=_xlfn.DECIMAL("1100",2)`: "12", `=_xlfn.DECIMAL("1100",2)`: "12",
`=_xlfn.DECIMAL("186A0",16)`: "100000", `=_xlfn.DECIMAL("186A0",16)`: "100000",
@ -186,6 +187,7 @@ func TestCalcCellValue(t *testing.T) {
// DEGREES // DEGREES
"=DEGREES(1)": "57.29577951308232", "=DEGREES(1)": "57.29577951308232",
"=DEGREES(2.5)": "143.2394487827058", "=DEGREES(2.5)": "143.2394487827058",
"=DEGREES(DEGREES(1))": "3282.806350011744",
// EVEN // EVEN
"=EVEN(23)": "24", "=EVEN(23)": "24",
"=EVEN(2.22)": "4", "=EVEN(2.22)": "4",
@ -193,19 +195,23 @@ func TestCalcCellValue(t *testing.T) {
"=EVEN(-0.3)": "-2", "=EVEN(-0.3)": "-2",
"=EVEN(-11)": "-12", "=EVEN(-11)": "-12",
"=EVEN(-4)": "-4", "=EVEN(-4)": "-4",
"=EVEN((0))": "0",
// EXP // EXP
"=EXP(100)": "2.6881171418161356E+43", "=EXP(100)": "2.6881171418161356E+43",
"=EXP(0.1)": "1.105170918075648", "=EXP(0.1)": "1.105170918075648",
"=EXP(0)": "1", "=EXP(0)": "1",
"=EXP(-5)": "0.006737946999085", "=EXP(-5)": "0.006737946999085",
"=EXP(EXP(0))": "2.718281828459045",
// FACT // FACT
"=FACT(3)": "6", "=FACT(3)": "6",
"=FACT(6)": "720", "=FACT(6)": "720",
"=FACT(10)": "3.6288E+06", "=FACT(10)": "3.6288E+06",
"=FACT(FACT(3))": "720",
// FACTDOUBLE // FACTDOUBLE
"=FACTDOUBLE(5)": "15", "=FACTDOUBLE(5)": "15",
"=FACTDOUBLE(8)": "384", "=FACTDOUBLE(8)": "384",
"=FACTDOUBLE(13)": "135135", "=FACTDOUBLE(13)": "135135",
"=FACTDOUBLE(FACTDOUBLE(1))": "1",
// FLOOR // FLOOR
"=FLOOR(26.75,0.1)": "26.700000000000003", "=FLOOR(26.75,0.1)": "26.700000000000003",
"=FLOOR(26.75,0.5)": "26.5", "=FLOOR(26.75,0.5)": "26.5",
@ -215,6 +221,7 @@ func TestCalcCellValue(t *testing.T) {
"=FLOOR(-26.75,-0.1)": "-26.700000000000003", "=FLOOR(-26.75,-0.1)": "-26.700000000000003",
"=FLOOR(-26.75,-1)": "-26", "=FLOOR(-26.75,-1)": "-26",
"=FLOOR(-26.75,-5)": "-25", "=FLOOR(-26.75,-5)": "-25",
"=FLOOR(FLOOR(26.75,1),1)": "26",
// _xlfn.FLOOR.MATH // _xlfn.FLOOR.MATH
"=_xlfn.FLOOR.MATH(58.55)": "58", "=_xlfn.FLOOR.MATH(58.55)": "58",
"=_xlfn.FLOOR.MATH(58.55,0.1)": "58.5", "=_xlfn.FLOOR.MATH(58.55,0.1)": "58.5",
@ -224,6 +231,7 @@ func TestCalcCellValue(t *testing.T) {
"=_xlfn.FLOOR.MATH(-58.55,1,-1)": "-58", "=_xlfn.FLOOR.MATH(-58.55,1,-1)": "-58",
"=_xlfn.FLOOR.MATH(-58.55,1,1)": "-59", // should be -58 "=_xlfn.FLOOR.MATH(-58.55,1,1)": "-59", // should be -58
"=_xlfn.FLOOR.MATH(-58.55,10)": "-60", "=_xlfn.FLOOR.MATH(-58.55,10)": "-60",
"=_xlfn.FLOOR.MATH(_xlfn.FLOOR.MATH(1),10)": "0",
// _xlfn.FLOOR.PRECISE // _xlfn.FLOOR.PRECISE
"=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.700000000000003", "=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.700000000000003",
"=_xlfn.FLOOR.PRECISE(26.75,0.5)": "26.5", "=_xlfn.FLOOR.PRECISE(26.75,0.5)": "26.5",
@ -234,6 +242,7 @@ func TestCalcCellValue(t *testing.T) {
"=_xlfn.FLOOR.PRECISE(-26.75,1)": "-27", "=_xlfn.FLOOR.PRECISE(-26.75,1)": "-27",
"=_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,-5)": "-30",
"=_xlfn.FLOOR.PRECISE(_xlfn.FLOOR.PRECISE(26.75),-5)": "25",
// GCD // GCD
"=GCD(0)": "0", "=GCD(0)": "0",
`=GCD("",1)`: "1", `=GCD("",1)`: "1",
@ -242,12 +251,14 @@ func TestCalcCellValue(t *testing.T) {
"=GCD(15,10,25)": "5", "=GCD(15,10,25)": "5",
"=GCD(0,8,12)": "4", "=GCD(0,8,12)": "4",
"=GCD(7,2)": "1", "=GCD(7,2)": "1",
"=GCD(1,GCD(1))": "1",
// INT // INT
"=INT(100.9)": "100", "=INT(100.9)": "100",
"=INT(5.22)": "5", "=INT(5.22)": "5",
"=INT(5.99)": "5", "=INT(5.99)": "5",
"=INT(-6.1)": "-7", "=INT(-6.1)": "-7",
"=INT(-100.9)": "-101", "=INT(-100.9)": "-101",
"=INT(INT(0))": "0",
// ISO.CEILING // ISO.CEILING
"=ISO.CEILING(22.25)": "23", "=ISO.CEILING(22.25)": "23",
"=ISO.CEILING(22.25,1)": "23", "=ISO.CEILING(22.25,1)": "23",
@ -257,6 +268,7 @@ func TestCalcCellValue(t *testing.T) {
"=ISO.CEILING(-22.25,0.1)": "-22.200000000000003", "=ISO.CEILING(-22.25,0.1)": "-22.200000000000003",
"=ISO.CEILING(-22.25,5)": "-20", "=ISO.CEILING(-22.25,5)": "-20",
"=ISO.CEILING(-22.25,0)": "0", "=ISO.CEILING(-22.25,0)": "0",
"=ISO.CEILING(1,ISO.CEILING(1,0))": "0",
// LCM // LCM
"=LCM(1,5)": "5", "=LCM(1,5)": "5",
"=LCM(15,10,25)": "150", "=LCM(15,10,25)": "150",
@ -265,26 +277,31 @@ func TestCalcCellValue(t *testing.T) {
"=LCM(7)": "7", "=LCM(7)": "7",
`=LCM("",1)`: "1", `=LCM("",1)`: "1",
`=LCM(0,0)`: "0", `=LCM(0,0)`: "0",
`=LCM(0,LCM(0,0))`: "0",
// LN // LN
"=LN(1)": "0", "=LN(1)": "0",
"=LN(100)": "4.605170185988092", "=LN(100)": "4.605170185988092",
"=LN(0.5)": "-0.693147180559945", "=LN(0.5)": "-0.693147180559945",
"=LN(LN(100))": "1.527179625807901",
// LOG // LOG
"=LOG(64,2)": "6", "=LOG(64,2)": "6",
"=LOG(100)": "2", "=LOG(100)": "2",
"=LOG(4,0.5)": "-2", "=LOG(4,0.5)": "-2",
"=LOG(500)": "2.698970004336019", "=LOG(500)": "2.698970004336019",
"=LOG(LOG(100))": "0.301029995663981",
// LOG10 // LOG10
"=LOG10(100)": "2", "=LOG10(100)": "2",
"=LOG10(1000)": "3", "=LOG10(1000)": "3",
"=LOG10(0.001)": "-3", "=LOG10(0.001)": "-3",
"=LOG10(25)": "1.397940008672038", "=LOG10(25)": "1.397940008672038",
"=LOG10(LOG10(100))": "0.301029995663981",
// MOD // MOD
"=MOD(6,4)": "2", "=MOD(6,4)": "2",
"=MOD(6,3)": "0", "=MOD(6,3)": "0",
"=MOD(6,2.5)": "1", "=MOD(6,2.5)": "1",
"=MOD(6,1.333)": "0.668", "=MOD(6,1.333)": "0.668",
"=MOD(-10.23,1)": "0.77", "=MOD(-10.23,1)": "0.77",
"=MOD(MOD(1,1),1)": "0",
// MROUND // MROUND
"=MROUND(333.7,0.5)": "333.5", "=MROUND(333.7,0.5)": "333.5",
"=MROUND(333.8,1)": "334", "=MROUND(333.8,1)": "334",
@ -294,9 +311,11 @@ func TestCalcCellValue(t *testing.T) {
"=MROUND(-555.7,-1)": "-556", "=MROUND(-555.7,-1)": "-556",
"=MROUND(-555.4,-1)": "-555", "=MROUND(-555.4,-1)": "-555",
"=MROUND(-1555,-1000)": "-2000", "=MROUND(-1555,-1000)": "-2000",
"=MROUND(MROUND(1,1),1)": "1",
// MULTINOMIAL // 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
"=_xlfn.MUNIT(4)": "", "=_xlfn.MUNIT(4)": "",
// ODD // ODD
@ -307,22 +326,27 @@ func TestCalcCellValue(t *testing.T) {
"=ODD(-1.3)": "-3", "=ODD(-1.3)": "-3",
"=ODD(-10)": "-11", "=ODD(-10)": "-11",
"=ODD(-3)": "-3", "=ODD(-3)": "-3",
"=ODD(ODD(1))": "1",
// PI // PI
"=PI()": "3.141592653589793", "=PI()": "3.141592653589793",
// POWER // POWER
"=POWER(4,2)": "16", "=POWER(4,2)": "16",
"=POWER(4,POWER(1,1))": "4",
// PRODUCT // 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
"=QUOTIENT(5,2)": "2", "=QUOTIENT(5,2)": "2",
"=QUOTIENT(4.5,3.1)": "1", "=QUOTIENT(4.5,3.1)": "1",
"=QUOTIENT(-10,3)": "-3", "=QUOTIENT(-10,3)": "-3",
"=QUOTIENT(QUOTIENT(1,2),3)": "0",
// RADIANS // RADIANS
"=RADIANS(50)": "0.872664625997165", "=RADIANS(50)": "0.872664625997165",
"=RADIANS(-180)": "-3.141592653589793", "=RADIANS(-180)": "-3.141592653589793",
"=RADIANS(180)": "3.141592653589793", "=RADIANS(180)": "3.141592653589793",
"=RADIANS(360)": "6.283185307179586", "=RADIANS(360)": "6.283185307179586",
"=RADIANS(RADIANS(360))": "0.109662271123215",
// ROMAN // ROMAN
"=ROMAN(499,0)": "CDXCIX", "=ROMAN(499,0)": "CDXCIX",
"=ROMAN(1999,0)": "MCMXCIX", "=ROMAN(1999,0)": "MCMXCIX",
@ -332,6 +356,7 @@ func TestCalcCellValue(t *testing.T) {
"=ROMAN(1999,4)": "MIM", "=ROMAN(1999,4)": "MIM",
"=ROMAN(1999,-1)": "MCMXCIX", "=ROMAN(1999,-1)": "MCMXCIX",
"=ROMAN(1999,5)": "MIM", "=ROMAN(1999,5)": "MIM",
"=ROMAN(1999,ODD(1))": "MLMVLIV",
// ROUND // ROUND
"=ROUND(100.319,1)": "100.30000000000001", "=ROUND(100.319,1)": "100.30000000000001",
"=ROUND(5.28,1)": "5.300000000000001", "=ROUND(5.28,1)": "5.300000000000001",
@ -342,6 +367,7 @@ func TestCalcCellValue(t *testing.T) {
"=ROUND(-22.45,1)": "-22.5", "=ROUND(-22.45,1)": "-22.5",
"=ROUND(999,-1)": "1000", "=ROUND(999,-1)": "1000",
"=ROUND(991,-1)": "990", "=ROUND(991,-1)": "990",
"=ROUND(ROUND(100,1),-1)": "100",
// ROUNDDOWN // ROUNDDOWN
"=ROUNDDOWN(99.999,1)": "99.9", "=ROUNDDOWN(99.999,1)": "99.9",
"=ROUNDDOWN(99.999,2)": "99.99000000000002", "=ROUNDDOWN(99.999,2)": "99.99000000000002",
@ -349,6 +375,7 @@ func TestCalcCellValue(t *testing.T) {
"=ROUNDDOWN(99.999,-1)": "90", "=ROUNDDOWN(99.999,-1)": "90",
"=ROUNDDOWN(-99.999,2)": "-99.99000000000002", "=ROUNDDOWN(-99.999,2)": "-99.99000000000002",
"=ROUNDDOWN(-99.999,-1)": "-90", "=ROUNDDOWN(-99.999,-1)": "-90",
"=ROUNDDOWN(ROUNDDOWN(100,1),-1)": "100",
// ROUNDUP` // ROUNDUP`
"=ROUNDUP(11.111,1)": "11.200000000000001", "=ROUNDUP(11.111,1)": "11.200000000000001",
"=ROUNDUP(11.111,2)": "11.120000000000003", "=ROUNDUP(11.111,2)": "11.120000000000003",
@ -356,32 +383,39 @@ func TestCalcCellValue(t *testing.T) {
"=ROUNDUP(11.111,-1)": "20", "=ROUNDUP(11.111,-1)": "20",
"=ROUNDUP(-11.111,2)": "-11.120000000000003", "=ROUNDUP(-11.111,2)": "-11.120000000000003",
"=ROUNDUP(-11.111,-1)": "-20", "=ROUNDUP(-11.111,-1)": "-20",
"=ROUNDUP(ROUNDUP(100,1),-1)": "100",
// SEC // SEC
"=_xlfn.SEC(-3.14159265358979)": "-1", "=_xlfn.SEC(-3.14159265358979)": "-1",
"=_xlfn.SEC(0)": "1", "=_xlfn.SEC(0)": "1",
"=_xlfn.SEC(_xlfn.SEC(0))": "0.54030230586814",
// SECH // SECH
"=_xlfn.SECH(-3.14159265358979)": "0.086266738334055", "=_xlfn.SECH(-3.14159265358979)": "0.086266738334055",
"=_xlfn.SECH(0)": "1", "=_xlfn.SECH(0)": "1",
"=_xlfn.SECH(_xlfn.SECH(0))": "0.648054273663886",
// SIGN // SIGN
"=SIGN(9.5)": "1", "=SIGN(9.5)": "1",
"=SIGN(-9.5)": "-1", "=SIGN(-9.5)": "-1",
"=SIGN(0)": "0", "=SIGN(0)": "0",
"=SIGN(0.00000001)": "1", "=SIGN(0.00000001)": "1",
"=SIGN(6-7)": "-1", "=SIGN(6-7)": "-1",
"=SIGN(SIGN(-1))": "-1",
// SIN // SIN
"=SIN(0.785398163)": "0.707106780905509", "=SIN(0.785398163)": "0.707106780905509",
"=SIN(SIN(1))": "0.745624141665558",
// SINH // SINH
"=SINH(0)": "0", "=SINH(0)": "0",
"=SINH(0.5)": "0.521095305493747", "=SINH(0.5)": "0.521095305493747",
"=SINH(-2)": "-3.626860407847019", "=SINH(-2)": "-3.626860407847019",
"=SINH(SINH(0))": "0",
// SQRT // SQRT
"=SQRT(4)": "2", "=SQRT(4)": "2",
`=SQRT("")`: "0", "=SQRT(SQRT(16))": "2",
// SQRTPI // SQRTPI
"=SQRTPI(5)": "3.963327297606011", "=SQRTPI(5)": "3.963327297606011",
"=SQRTPI(0.2)": "0.792665459521202", "=SQRTPI(0.2)": "0.792665459521202",
"=SQRTPI(100)": "17.72453850905516", "=SQRTPI(100)": "17.72453850905516",
"=SQRTPI(0)": "0", "=SQRTPI(0)": "0",
"=SQRTPI(SQRTPI(0))": "0",
// SUM // SUM
"=SUM(1,2)": "3", "=SUM(1,2)": "3",
`=SUM("",1,2)`: "3", `=SUM("",1,2)`: "3",
@ -415,13 +449,16 @@ func TestCalcCellValue(t *testing.T) {
"=SUMSQ(A1:A4)": "14", "=SUMSQ(A1:A4)": "14",
"=SUMSQ(A1,B1,A2,B2,6)": "82", "=SUMSQ(A1,B1,A2,B2,6)": "82",
`=SUMSQ("",A1,B1,A2,B2,6)`: "82", `=SUMSQ("",A1,B1,A2,B2,6)`: "82",
`=SUMSQ(1,SUMSQ(1))`: "2",
// TAN // TAN
"=TAN(1.047197551)": "1.732050806782486", "=TAN(1.047197551)": "1.732050806782486",
"=TAN(0)": "0", "=TAN(0)": "0",
"=TAN(TAN(0))": "0",
// TANH // TANH
"=TANH(0)": "0", "=TANH(0)": "0",
"=TANH(0.5)": "0.46211715726001", "=TANH(0.5)": "0.46211715726001",
"=TANH(-2)": "-0.964027580075817", "=TANH(-2)": "-0.964027580075817",
"=TANH(TANH(0))": "0",
// TRUNC // TRUNC
"=TRUNC(99.999,1)": "99.9", "=TRUNC(99.999,1)": "99.9",
"=TRUNC(99.999,2)": "99.99", "=TRUNC(99.999,2)": "99.99",
@ -429,13 +466,16 @@ func TestCalcCellValue(t *testing.T) {
"=TRUNC(99.999,-1)": "90", "=TRUNC(99.999,-1)": "90",
"=TRUNC(-99.999,2)": "-99.99", "=TRUNC(-99.999,2)": "-99.99",
"=TRUNC(-99.999,-1)": "-90", "=TRUNC(-99.999,-1)": "-90",
"=TRUNC(TRUNC(1),-1)": "0",
// Statistical Functions // Statistical Functions
// COUNTA // COUNTA
`=COUNTA()`: "0", `=COUNTA()`: "0",
`=COUNTA(A1:A5,B2:B5,"text",1,2)`: "8", `=COUNTA(A1:A5,B2:B5,"text",1,2)`: "8",
`=COUNTA(COUNTA(1))`: "1",
// MEDIAN // MEDIAN
"=MEDIAN(A1:A5,12)": "2", "=MEDIAN(A1:A5,12)": "2",
"=MEDIAN(A1:A5)": "1.5", "=MEDIAN(A1:A5)": "1.5",
"=MEDIAN(A1:A5,MEDIAN(A1:A5,12))": "2",
// Information Functions // Information Functions
// ISBLANK // ISBLANK
"=ISBLANK(A1)": "FALSE", "=ISBLANK(A1)": "FALSE",
@ -707,7 +747,7 @@ func TestCalcCellValue(t *testing.T) {
`=MULTINOMIAL("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", `=MULTINOMIAL("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// _xlfn.MUNIT // _xlfn.MUNIT
"=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently "=_xlfn.MUNIT()": "MUNIT requires 1 numeric argument", // not support currently
`=_xlfn.MUNIT("X")`: "strconv.Atoi: parsing \"X\": invalid syntax", // not support currently `=_xlfn.MUNIT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", // not support currently
// ODD // ODD
"=ODD()": "ODD requires 1 numeric argument", "=ODD()": "ODD requires 1 numeric argument",
`=ODD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", `=ODD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
@ -732,8 +772,8 @@ func TestCalcCellValue(t *testing.T) {
// RAND // RAND
"=RAND(1)": "RAND accepts no arguments", "=RAND(1)": "RAND accepts no arguments",
// RANDBETWEEN // RANDBETWEEN
`=RANDBETWEEN("X",1)`: "strconv.ParseInt: parsing \"X\": invalid syntax", `=RANDBETWEEN("X",1)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
`=RANDBETWEEN(1,"X")`: "strconv.ParseInt: parsing \"X\": invalid syntax", `=RANDBETWEEN(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments", "=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments",
"=RANDBETWEEN(2,1)": "#NUM!", "=RANDBETWEEN(2,1)": "#NUM!",
// ROMAN // ROMAN
@ -770,6 +810,7 @@ func TestCalcCellValue(t *testing.T) {
`=SINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", `=SINH("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// SQRT // SQRT
"=SQRT()": "SQRT requires 1 numeric argument", "=SQRT()": "SQRT requires 1 numeric argument",
`=SQRT("")`: "strconv.ParseFloat: parsing \"\": invalid syntax",
`=SQRT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax", `=SQRT("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
"=SQRT(-1)": "#NUM!", "=SQRT(-1)": "#NUM!",
// SQRTPI // SQRTPI