diff --git a/calc.go b/calc.go index 3d4a8be169b7dc81519aa7858ae783cb486c661f..61b6dac773fbbf584de42e183ce88e2bd26de123 100644 --- a/calc.go +++ b/calc.go @@ -644,6 +644,7 @@ func (fn *formulaFuncs) ABS(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Abs(val)) @@ -663,6 +664,7 @@ func (fn *formulaFuncs) ACOS(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Acos(val)) @@ -681,6 +683,7 @@ func (fn *formulaFuncs) ACOSH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Acosh(val)) @@ -700,6 +703,7 @@ func (fn *formulaFuncs) ACOT(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Pi/2-math.Atan(val)) @@ -718,6 +722,7 @@ func (fn *formulaFuncs) ACOTH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Atanh(1/val)) @@ -774,6 +779,7 @@ func (fn *formulaFuncs) ASIN(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Asin(val)) @@ -792,6 +798,7 @@ func (fn *formulaFuncs) ASINH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Asinh(val)) @@ -811,6 +818,7 @@ func (fn *formulaFuncs) ATAN(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Atan(val)) @@ -829,6 +837,7 @@ func (fn *formulaFuncs) ATANH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Atanh(val)) @@ -848,34 +857,17 @@ func (fn *formulaFuncs) ATAN2(argsList *list.List) (result string, err error) { } var x, y float64 if x, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if y, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Atan2(x, y)) return } -// gcd returns the greatest common divisor of two supplied integers. -func gcd(x, y float64) float64 { - x, y = math.Trunc(x), math.Trunc(y) - if x == 0 { - return y - } - if y == 0 { - return x - } - for x != y { - if x > y { - x = x - y - } else { - y = y - x - } - } - return x -} - // BASE function converts a number into a supplied base (radix), and returns a // text representation of the calculated value. The syntax of the function is: // @@ -893,9 +885,11 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) { var number float64 var radix, minLength int if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if radix, err = strconv.Atoi(argsList.Front().Next().Value.(formulaArg).Value); err != nil { + err = errors.New(formulaErrorVALUE) return } if radix < 2 || radix > 36 { @@ -904,6 +898,7 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) { } if argsList.Len() > 2 { if minLength, err = strconv.Atoi(argsList.Back().Value.(formulaArg).Value); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -931,6 +926,7 @@ func (fn *formulaFuncs) CEILING(argsList *list.List) (result string, err error) } number, significance, res := 0.0, 1.0, 0.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -938,6 +934,7 @@ func (fn *formulaFuncs) CEILING(argsList *list.List) (result string, err error) } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -973,6 +970,7 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err err } number, significance, mode := 0.0, 1.0, 1.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -980,6 +978,7 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err err } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -989,6 +988,7 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) (result string, err err } if argsList.Len() > 2 { if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -1021,6 +1021,7 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) (result string, err } number, significance := 0.0, 1.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -1032,6 +1033,7 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) (result string, err } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } significance = math.Abs(significance) @@ -1062,9 +1064,11 @@ func (fn *formulaFuncs) COMBIN(argsList *list.List) (result string, err error) { } number, chosen, val := 0.0, 0.0, 1.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } number, chosen = math.Trunc(number), math.Trunc(chosen) @@ -1095,9 +1099,11 @@ func (fn *formulaFuncs) COMBINA(argsList *list.List) (result string, err error) } var number, chosen float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } number, chosen = math.Trunc(number), math.Trunc(chosen) @@ -1131,6 +1137,7 @@ func (fn *formulaFuncs) COS(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Cos(val)) @@ -1149,6 +1156,7 @@ func (fn *formulaFuncs) COSH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Cosh(val)) @@ -1167,10 +1175,11 @@ func (fn *formulaFuncs) COT(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val == 0 { - err = errors.New(formulaErrorNAME) + err = errors.New(formulaErrorDIV) return } result = fmt.Sprintf("%g", math.Tan(val)) @@ -1189,10 +1198,11 @@ func (fn *formulaFuncs) COTH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val == 0 { - err = errors.New(formulaErrorNAME) + err = errors.New(formulaErrorDIV) return } result = fmt.Sprintf("%g", math.Tanh(val)) @@ -1211,10 +1221,11 @@ func (fn *formulaFuncs) CSC(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val == 0 { - err = errors.New(formulaErrorNAME) + err = errors.New(formulaErrorDIV) return } result = fmt.Sprintf("%g", 1/math.Sin(val)) @@ -1233,10 +1244,11 @@ func (fn *formulaFuncs) CSCH(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val == 0 { - err = errors.New(formulaErrorNAME) + err = errors.New(formulaErrorDIV) return } result = fmt.Sprintf("%g", 1/math.Sinh(val)) @@ -1256,6 +1268,7 @@ func (fn *formulaFuncs) DECIMAL(argsList *list.List) (result string, err error) var text = argsList.Front().Value.(formulaArg).Value var radix int if radix, err = strconv.Atoi(argsList.Back().Value.(formulaArg).Value); err != nil { + err = errors.New(formulaErrorVALUE) return } if len(text) > 2 && (strings.HasPrefix(text, "0x") || strings.HasPrefix(text, "0X")) { @@ -1263,7 +1276,7 @@ func (fn *formulaFuncs) DECIMAL(argsList *list.List) (result string, err error) } val, err := strconv.ParseInt(text, radix, 64) if err != nil { - err = errors.New(formulaErrorNUM) + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", float64(val)) @@ -1282,10 +1295,11 @@ func (fn *formulaFuncs) DEGREES(argsList *list.List) (result string, err error) } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val == 0 { - err = errors.New(formulaErrorNAME) + err = errors.New(formulaErrorDIV) return } result = fmt.Sprintf("%g", 180.0/math.Pi*val) @@ -1305,6 +1319,7 @@ func (fn *formulaFuncs) EVEN(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } sign := math.Signbit(number) @@ -1333,6 +1348,7 @@ func (fn *formulaFuncs) EXP(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = strings.ToUpper(fmt.Sprintf("%g", math.Exp(number))) @@ -1360,6 +1376,7 @@ func (fn *formulaFuncs) FACT(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -1381,10 +1398,12 @@ func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) (result string, err erro } number, val := 0.0, 1.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { err = errors.New(formulaErrorNUM) + return } for i := math.Trunc(number); i > 1; i -= 2 { val *= i @@ -1405,13 +1424,16 @@ func (fn *formulaFuncs) FLOOR(argsList *list.List) (result string, err error) { } var number, significance float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if significance < 0 && number >= 0 { err = errors.New(formulaErrorNUM) + return } val := number val, res := math.Modf(val / significance) @@ -1440,6 +1462,7 @@ func (fn *formulaFuncs) FLOORMATH(argsList *list.List) (result string, err error } number, significance, mode := 0.0, 1.0, 1.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -1447,6 +1470,7 @@ func (fn *formulaFuncs) FLOORMATH(argsList *list.List) (result string, err error } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Front().Next().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -1456,6 +1480,7 @@ func (fn *formulaFuncs) FLOORMATH(argsList *list.List) (result string, err error } if argsList.Len() > 2 { if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -1483,6 +1508,7 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) (result string, err er } var number, significance float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -1494,6 +1520,7 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) (result string, err er } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } significance = math.Abs(significance) @@ -1512,6 +1539,25 @@ func (fn *formulaFuncs) FLOORPRECISE(argsList *list.List) (result string, err er return } +// gcd returns the greatest common divisor of two supplied integers. +func gcd(x, y float64) float64 { + x, y = math.Trunc(x), math.Trunc(y) + if x == 0 { + return y + } + if y == 0 { + return x + } + for x != y { + if x > y { + x = x - y + } else { + y = y - x + } + } + return x +} + // GCD function returns the greatest common divisor of two or more supplied // integers. The syntax of the function is: // @@ -1532,6 +1578,7 @@ func (fn *formulaFuncs) GCD(argsList *list.List) (result string, err error) { continue } if val, err = strconv.ParseFloat(token, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } nums = append(nums, val) @@ -1568,6 +1615,7 @@ func (fn *formulaFuncs) INT(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } val, frac := math.Modf(number) @@ -1595,6 +1643,7 @@ func (fn *formulaFuncs) ISOCEILING(argsList *list.List) (result string, err erro } var number, significance float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number < 0 { @@ -1606,6 +1655,7 @@ func (fn *formulaFuncs) ISOCEILING(argsList *list.List) (result string, err erro } if argsList.Len() > 1 { if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } significance = math.Abs(significance) @@ -1654,6 +1704,7 @@ func (fn *formulaFuncs) LCM(argsList *list.List) (result string, err error) { continue } if val, err = strconv.ParseFloat(token, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } nums = append(nums, val) @@ -1690,6 +1741,7 @@ func (fn *formulaFuncs) LN(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Log(number)) @@ -1712,10 +1764,12 @@ func (fn *formulaFuncs) LOG(argsList *list.List) (result string, err error) { } number, base := 0.0, 10.0 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if argsList.Len() > 1 { if base, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } } @@ -1747,6 +1801,7 @@ func (fn *formulaFuncs) LOG10(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Log10(number)) @@ -1835,9 +1890,11 @@ func (fn *formulaFuncs) MOD(argsList *list.List) (result string, err error) { } var number, divisor float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if divisor, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if divisor == 0 { @@ -1864,9 +1921,11 @@ func (fn *formulaFuncs) MROUND(argsList *list.List) (result string, err error) { } var number, multiple float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if multiple, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if multiple == 0 { @@ -1900,6 +1959,7 @@ func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) (result string, err err continue } if val, err = strconv.ParseFloat(token.Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } num += val @@ -1921,6 +1981,7 @@ func (fn *formulaFuncs) MUNIT(argsList *list.List) (result string, err error) { } var dimension int if dimension, err = strconv.Atoi(argsList.Front().Value.(formulaArg).Value); err != nil { + err = errors.New(formulaErrorVALUE) return } matrix := make([][]float64, 0, dimension) @@ -1951,6 +2012,7 @@ func (fn *formulaFuncs) ODD(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if number == 0 { @@ -1997,9 +2059,11 @@ func (fn *formulaFuncs) POWER(argsList *list.List) (result string, err error) { } var x, y float64 if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if x == 0 && y == 0 { @@ -2027,6 +2091,7 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) (result string, err error) continue } if val, err = strconv.ParseFloat(token.Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } product = product * val @@ -2047,9 +2112,11 @@ func (fn *formulaFuncs) QUOTIENT(argsList *list.List) (result string, err error) } var x, y float64 if x, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if y, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if y == 0 { @@ -2071,6 +2138,7 @@ func (fn *formulaFuncs) RADIANS(argsList *list.List) (result string, err error) } var angle float64 if angle, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Pi/180.0*angle) @@ -2103,9 +2171,11 @@ func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) (result string, err err } var bottom, top int64 if bottom, err = strconv.ParseInt(argsList.Front().Value.(formulaArg).Value, 10, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if top, err = strconv.ParseInt(argsList.Back().Value.(formulaArg).Value, 10, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if top < bottom { @@ -2148,10 +2218,12 @@ func (fn *formulaFuncs) ROMAN(argsList *list.List) (result string, err error) { var number float64 var form int if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if argsList.Len() > 1 { if form, err = strconv.Atoi(argsList.Back().Value.(formulaArg).Value); err != nil { + err = errors.New(formulaErrorVALUE) return } if form < 0 { @@ -2231,9 +2303,11 @@ func (fn *formulaFuncs) ROUND(argsList *list.List) (result string, err error) { } var number, digits float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", fn.round(number, digits, closest)) @@ -2252,9 +2326,11 @@ func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) (result string, err error } var number, digits float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", fn.round(number, digits, down)) @@ -2273,9 +2349,11 @@ func (fn *formulaFuncs) ROUNDUP(argsList *list.List) (result string, err error) } var number, digits float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", fn.round(number, digits, up)) @@ -2294,6 +2372,7 @@ func (fn *formulaFuncs) SEC(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Cos(number)) @@ -2312,6 +2391,7 @@ func (fn *formulaFuncs) SECH(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", 1/math.Cosh(number)) @@ -2332,6 +2412,7 @@ func (fn *formulaFuncs) SIGN(argsList *list.List) (result string, err error) { } var val float64 if val, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if val < 0 { @@ -2358,6 +2439,7 @@ func (fn *formulaFuncs) SIN(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Sin(number)) @@ -2376,6 +2458,7 @@ func (fn *formulaFuncs) SINH(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Sinh(number)) @@ -2399,6 +2482,7 @@ func (fn *formulaFuncs) SQRT(argsList *list.List) (result string, err error) { return } if res, err = strconv.ParseFloat(value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if res < 0 { @@ -2421,6 +2505,7 @@ func (fn *formulaFuncs) SQRTPI(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Sqrt(number*math.Pi)) @@ -2440,6 +2525,7 @@ func (fn *formulaFuncs) SUM(argsList *list.List) (result string, err error) { continue } if val, err = strconv.ParseFloat(token.Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } sum += val @@ -2461,6 +2547,7 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) (result string, err error) { continue } if val, err = strconv.ParseFloat(token.Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } sq += val * val @@ -2481,6 +2568,7 @@ func (fn *formulaFuncs) TAN(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Tan(number)) @@ -2499,6 +2587,7 @@ func (fn *formulaFuncs) TANH(argsList *list.List) (result string, err error) { } var number float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } result = fmt.Sprintf("%g", math.Tanh(number)) @@ -2517,10 +2606,12 @@ func (fn *formulaFuncs) TRUNC(argsList *list.List) (result string, err error) { } var number, digits, adjust, rtrim float64 if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } if argsList.Len() > 1 { if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).Value, 64); err != nil { + err = errors.New(formulaErrorVALUE) return } digits = math.Floor(digits) diff --git a/calc_test.go b/calc_test.go index fc107cb4221a4a13e5f89711705f19df84476f26..7592078c743cbbc8188c21466d1eec490c156ba3 100644 --- a/calc_test.go +++ b/calc_test.go @@ -77,13 +77,16 @@ func TestCalcCellValue(t *testing.T) { "=CEILING(-22.25,-0.1)": "-22.3", "=CEILING(-22.25,-1)": "-23", "=CEILING(-22.25,-5)": "-25", + "=CEILING(22.25)": "23", // _xlfn.CEILING.MATH - "=_xlfn.CEILING.MATH(15.25,1)": "16", - "=_xlfn.CEILING.MATH(15.25,0.1)": "15.3", - "=_xlfn.CEILING.MATH(15.25,5)": "20", - "=_xlfn.CEILING.MATH(-15.25,1)": "-15", - "=_xlfn.CEILING.MATH(-15.25,1,1)": "-15", // should be 16 - "=_xlfn.CEILING.MATH(-15.25,10)": "-10", + "=_xlfn.CEILING.MATH(15.25,1)": "16", + "=_xlfn.CEILING.MATH(15.25,0.1)": "15.3", + "=_xlfn.CEILING.MATH(15.25,5)": "20", + "=_xlfn.CEILING.MATH(-15.25,1)": "-15", + "=_xlfn.CEILING.MATH(-15.25,1,1)": "-15", // should be 16 + "=_xlfn.CEILING.MATH(-15.25,10)": "-10", + "=_xlfn.CEILING.MATH(-15.25)": "-15", + "=_xlfn.CEILING.MATH(-15.25,-5,-1)": "-10", // _xlfn.CEILING.PRECISE "=_xlfn.CEILING.PRECISE(22.25,0.1)": "22.3", "=_xlfn.CEILING.PRECISE(22.25,0.5)": "22.5", @@ -101,6 +104,7 @@ func TestCalcCellValue(t *testing.T) { "=COMBIN(6,4)": "15", "=COMBIN(6,5)": "6", "=COMBIN(6,6)": "1", + "=COMBIN(0,0)": "1", // _xlfn.COMBINA "=_xlfn.COMBINA(6,1)": "6", "=_xlfn.COMBINA(6,2)": "21", @@ -108,6 +112,7 @@ func TestCalcCellValue(t *testing.T) { "=_xlfn.COMBINA(6,4)": "126", "=_xlfn.COMBINA(6,5)": "252", "=_xlfn.COMBINA(6,6)": "462", + "=_xlfn.COMBINA(0,0)": "0", // COS "=COS(0.785398163)": "0.707106781467586", "=COS(0)": "1", @@ -125,10 +130,11 @@ func TestCalcCellValue(t *testing.T) { // _xlfn.CSCH "=_xlfn.CSCH(-3.14159265358979)": "-0.08658953753004724", // _xlfn.DECIMAL - `=_xlfn.DECIMAL("1100",2)`: "12", - `=_xlfn.DECIMAL("186A0",16)`: "100000", - `=_xlfn.DECIMAL("31L0",32)`: "100000", - `=_xlfn.DECIMAL("70122",8)`: "28754", + `=_xlfn.DECIMAL("1100",2)`: "12", + `=_xlfn.DECIMAL("186A0",16)`: "100000", + `=_xlfn.DECIMAL("31L0",32)`: "100000", + `=_xlfn.DECIMAL("70122",8)`: "28754", + `=_xlfn.DECIMAL("0x70122",8)`: "28754", // DEGREES "=DEGREES(1)": "57.29577951308232", "=DEGREES(2.5)": "143.2394487827058", @@ -181,6 +187,9 @@ func TestCalcCellValue(t *testing.T) { "=_xlfn.FLOOR.PRECISE(-26.75,-1)": "-27", "=_xlfn.FLOOR.PRECISE(-26.75,-5)": "-30", // GCD + "=GCD(0)": "0", + `=GCD("",1)`: "1", + "=GCD(1,0)": "1", "=GCD(1,5)": "1", "=GCD(15,10,25)": "5", "=GCD(0,8,12)": "4", @@ -199,11 +208,15 @@ func TestCalcCellValue(t *testing.T) { "=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", // 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", // LN "=LN(1)": "0", "=LN(100)": "4.605170185988092", @@ -219,10 +232,11 @@ func TestCalcCellValue(t *testing.T) { "=LOG10(0.001)": "-3", "=LOG10(25)": "1.3979400086720375", // MOD - "=MOD(6,4)": "2", - "=MOD(6,3)": "0", - "=MOD(6,2.5)": "1", - "=MOD(6,1.333)": "0.6680000000000001", + "=MOD(6,4)": "2", + "=MOD(6,3)": "0", + "=MOD(6,2.5)": "1", + "=MOD(6,1.333)": "0.6680000000000001", + "=MOD(-10.23,1)": "0.7699999999999996", // MROUND "=MROUND(333.7,0.5)": "333.5", "=MROUND(333.8,1)": "334", @@ -233,7 +247,8 @@ func TestCalcCellValue(t *testing.T) { "=MROUND(-555.4,-1)": "-555", "=MROUND(-1555,-1000)": "-2000", // MULTINOMIAL - "=MULTINOMIAL(3,1,2,5)": "27720", + "=MULTINOMIAL(3,1,2,5)": "27720", + `=MULTINOMIAL("",3,1,2,5)`: "27720", // _xlfn.MUNIT "=_xlfn.MUNIT(4)": "", // not support currently // ODD @@ -249,7 +264,8 @@ func TestCalcCellValue(t *testing.T) { // POWER "=POWER(4,2)": "16", // PRODUCT - "=PRODUCT(3,6)": "18", + "=PRODUCT(3,6)": "18", + `=PRODUCT("",3,6)`: "18", // QUOTIENT "=QUOTIENT(5,2)": "2", "=QUOTIENT(4.5,3.1)": "1", @@ -260,12 +276,14 @@ func TestCalcCellValue(t *testing.T) { "=RADIANS(180)": "3.141592653589793", "=RADIANS(360)": "6.283185307179586", // 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(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", // ROUND "=ROUND(100.319,1)": "100.30000000000001", "=ROUND(5.28,1)": "5.300000000000001", @@ -317,6 +335,7 @@ func TestCalcCellValue(t *testing.T) { "=SQRTPI(0)": "0", // SUM "=SUM(1,2)": "3", + `=SUM("",1,2)`: "3", "=SUM(1,2+3)": "6", "=SUM(SUM(1,2),2)": "5", "=(-2-SUM(-4+7))*5": "-25", @@ -330,8 +349,9 @@ func TestCalcCellValue(t *testing.T) { "=1+SUM(SUM(1,2*3),4)*-4/2+5+(4+2)*3": "2", "=1+SUM(SUM(1,2*3),4)*4/3+5+(4+2)*3": "38.666666666666664", // SUMSQ - "=SUMSQ(A1:A4)": "14", - "=SUMSQ(A1,B1,A2,B2,6)": "82", + "=SUMSQ(A1:A4)": "14", + "=SUMSQ(A1,B1,A2,B2,6)": "82", + `=SUMSQ("",A1,B1,A2,B2,6)`: "82", // TAN "=TAN(1.047197551)": "1.732050806782486", "=TAN(0)": "0", @@ -356,173 +376,269 @@ func TestCalcCellValue(t *testing.T) { } mathCalcError := map[string]string{ // ABS - "=ABS()": "ABS requires 1 numeric argument", - "=ABS(~)": `cannot convert cell "~" to coordinates: invalid cell name "~"`, + "=ABS()": "ABS requires 1 numeric argument", + `=ABS("X")`: "#VALUE!", + "=ABS(~)": `cannot convert cell "~" to coordinates: invalid cell name "~"`, // ACOS - "=ACOS()": "ACOS requires 1 numeric argument", + "=ACOS()": "ACOS requires 1 numeric argument", + `=ACOS("X")`: "#VALUE!", // ACOSH - "=ACOSH()": "ACOSH requires 1 numeric argument", + "=ACOSH()": "ACOSH requires 1 numeric argument", + `=ACOSH("X")`: "#VALUE!", // _xlfn.ACOT - "=_xlfn.ACOT()": "ACOT requires 1 numeric argument", + "=_xlfn.ACOT()": "ACOT requires 1 numeric argument", + `=_xlfn.ACOT("X")`: "#VALUE!", // _xlfn.ACOTH - "=_xlfn.ACOTH()": "ACOTH requires 1 numeric argument", + "=_xlfn.ACOTH()": "ACOTH requires 1 numeric argument", + `=_xlfn.ACOTH("X")`: "#VALUE!", // _xlfn.ARABIC "=_xlfn.ARABIC()": "ARABIC requires 1 numeric argument", // ASIN - "=ASIN()": "ASIN requires 1 numeric argument", + "=ASIN()": "ASIN requires 1 numeric argument", + `=ASIN("X")`: "#VALUE!", // ASINH - "=ASINH()": "ASINH requires 1 numeric argument", + "=ASINH()": "ASINH requires 1 numeric argument", + `=ASINH("X")`: "#VALUE!", // ATAN - "=ATAN()": "ATAN requires 1 numeric argument", + "=ATAN()": "ATAN requires 1 numeric argument", + `=ATAN("X")`: "#VALUE!", // ATANH - "=ATANH()": "ATANH requires 1 numeric argument", + "=ATANH()": "ATANH requires 1 numeric argument", + `=ATANH("X")`: "#VALUE!", // ATAN2 - "=ATAN2()": "ATAN2 requires 2 numeric arguments", + "=ATAN2()": "ATAN2 requires 2 numeric arguments", + `=ATAN2("X",0)`: "#VALUE!", + `=ATAN2(0,"X")`: "#VALUE!", // BASE "=BASE()": "BASE requires at least 2 arguments", "=BASE(1,2,3,4)": "BASE allows at most 3 arguments", "=BASE(1,1)": "radix must be an integer >= 2 and <= 36", + `=BASE("X",2)`: "#VALUE!", + `=BASE(1,"X")`: "#VALUE!", + `=BASE(1,2,"X")`: "#VALUE!", // CEILING "=CEILING()": "CEILING requires at least 1 argument", "=CEILING(1,2,3)": "CEILING allows at most 2 arguments", "=CEILING(1,-1)": "negative sig to CEILING invalid", + `=CEILING("X",0)`: "#VALUE!", + `=CEILING(0,"X")`: "#VALUE!", // _xlfn.CEILING.MATH "=_xlfn.CEILING.MATH()": "CEILING.MATH requires at least 1 argument", "=_xlfn.CEILING.MATH(1,2,3,4)": "CEILING.MATH allows at most 3 arguments", + `=_xlfn.CEILING.MATH("X")`: "#VALUE!", + `=_xlfn.CEILING.MATH(1,"X")`: "#VALUE!", + `=_xlfn.CEILING.MATH(1,2,"X")`: "#VALUE!", // _xlfn.CEILING.PRECISE "=_xlfn.CEILING.PRECISE()": "CEILING.PRECISE requires at least 1 argument", "=_xlfn.CEILING.PRECISE(1,2,3)": "CEILING.PRECISE allows at most 2 arguments", + `=_xlfn.CEILING.PRECISE("X",2)`: "#VALUE!", + `=_xlfn.CEILING.PRECISE(1,"X")`: "#VALUE!", // COMBIN - "=COMBIN()": "COMBIN requires 2 argument", - "=COMBIN(-1,1)": "COMBIN requires number >= number_chosen", + "=COMBIN()": "COMBIN requires 2 argument", + "=COMBIN(-1,1)": "COMBIN requires number >= number_chosen", + `=COMBIN("X",1)`: "#VALUE!", + `=COMBIN(-1,"X")`: "#VALUE!", // _xlfn.COMBINA - "=_xlfn.COMBINA()": "COMBINA requires 2 argument", - "=_xlfn.COMBINA(-1,1)": "COMBINA requires number > number_chosen", - "=_xlfn.COMBINA(-1,-1)": "COMBIN requires number >= number_chosen", + "=_xlfn.COMBINA()": "COMBINA requires 2 argument", + "=_xlfn.COMBINA(-1,1)": "COMBINA requires number > number_chosen", + "=_xlfn.COMBINA(-1,-1)": "COMBIN requires number >= number_chosen", + `=_xlfn.COMBINA("X",1)`: "#VALUE!", + `=_xlfn.COMBINA(-1,"X")`: "#VALUE!", // COS - "=COS()": "COS requires 1 numeric argument", + "=COS()": "COS requires 1 numeric argument", + `=COS("X")`: "#VALUE!", // COSH - "=COSH()": "COSH requires 1 numeric argument", + "=COSH()": "COSH requires 1 numeric argument", + `=COSH("X")`: "#VALUE!", // _xlfn.COT - "=COT()": "COT requires 1 numeric argument", + "=COT()": "COT requires 1 numeric argument", + `=COT("X")`: "#VALUE!", + "=COT(0)": "#DIV/0!", // _xlfn.COTH - "=COTH()": "COTH requires 1 numeric argument", + "=COTH()": "COTH requires 1 numeric argument", + `=COTH("X")`: "#VALUE!", + "=COTH(0)": "#DIV/0!", // _xlfn.CSC - "=_xlfn.CSC()": "CSC requires 1 numeric argument", - "=_xlfn.CSC(0)": "#NAME?", + "=_xlfn.CSC()": "CSC requires 1 numeric argument", + `=_xlfn.CSC("X")`: "#VALUE!", + "=_xlfn.CSC(0)": "#DIV/0!", // _xlfn.CSCH - "=_xlfn.CSCH()": "CSCH requires 1 numeric argument", - "=_xlfn.CSCH(0)": "#NAME?", + "=_xlfn.CSCH()": "CSCH requires 1 numeric argument", + `=_xlfn.CSCH("X")`: "#VALUE!", + "=_xlfn.CSCH(0)": "#DIV/0!", // _xlfn.DECIMAL "=_xlfn.DECIMAL()": "DECIMAL requires 2 numeric arguments", - `=_xlfn.DECIMAL("2000", 2)`: "#NUM!", + `=_xlfn.DECIMAL("X", 2)`: "#VALUE!", + `=_xlfn.DECIMAL(2000, "X")`: "#VALUE!", // DEGREES - "=DEGREES()": "DEGREES requires 1 numeric argument", + "=DEGREES()": "DEGREES requires 1 numeric argument", + `=DEGREES("X")`: "#VALUE!", + "=DEGREES(0)": "#DIV/0!", // EVEN - "=EVEN()": "EVEN requires 1 numeric argument", + "=EVEN()": "EVEN requires 1 numeric argument", + `=EVEN("X")`: "#VALUE!", // EXP - "=EXP()": "EXP requires 1 numeric argument", + "=EXP()": "EXP requires 1 numeric argument", + `=EXP("X")`: "#VALUE!", // FACT - "=FACT()": "FACT requires 1 numeric argument", - "=FACT(-1)": "#NUM!", + "=FACT()": "FACT requires 1 numeric argument", + `=FACT("X")`: "#VALUE!", + "=FACT(-1)": "#NUM!", // FACTDOUBLE - "=FACTDOUBLE()": "FACTDOUBLE requires 1 numeric argument", - "=FACTDOUBLE(-1)": "#NUM!", + "=FACTDOUBLE()": "FACTDOUBLE requires 1 numeric argument", + `=FACTDOUBLE("X")`: "#VALUE!", + "=FACTDOUBLE(-1)": "#NUM!", // FLOOR - "=FLOOR()": "FLOOR requires 2 numeric arguments", - "=FLOOR(1,-1)": "#NUM!", + "=FLOOR()": "FLOOR requires 2 numeric arguments", + `=FLOOR("X",-1)`: "#VALUE!", + `=FLOOR(1,"X")`: "#VALUE!", + "=FLOOR(1,-1)": "#NUM!", // _xlfn.FLOOR.MATH "=_xlfn.FLOOR.MATH()": "FLOOR.MATH requires at least 1 argument", "=_xlfn.FLOOR.MATH(1,2,3,4)": "FLOOR.MATH allows at most 3 arguments", + `=_xlfn.FLOOR.MATH("X",2,3)`: "#VALUE!", + `=_xlfn.FLOOR.MATH(1,"X",3)`: "#VALUE!", + `=_xlfn.FLOOR.MATH(1,2,"X")`: "#VALUE!", // _xlfn.FLOOR.PRECISE "=_xlfn.FLOOR.PRECISE()": "FLOOR.PRECISE requires at least 1 argument", "=_xlfn.FLOOR.PRECISE(1,2,3)": "FLOOR.PRECISE allows at most 2 arguments", + `=_xlfn.FLOOR.PRECISE("X",2)`: "#VALUE!", + `=_xlfn.FLOOR.PRECISE(1,"X")`: "#VALUE!", // GCD "=GCD()": "GCD requires at least 1 argument", "=GCD(-1)": "GCD only accepts positive arguments", "=GCD(1,-1)": "GCD only accepts positive arguments", + `=GCD("X")`: "#VALUE!", // INT - "=INT()": "INT requires 1 numeric argument", + "=INT()": "INT requires 1 numeric argument", + `=INT("X")`: "#VALUE!", // ISO.CEILING "=ISO.CEILING()": "ISO.CEILING requires at least 1 argument", "=ISO.CEILING(1,2,3)": "ISO.CEILING allows at most 2 arguments", + `=ISO.CEILING("X",2)`: "#VALUE!", + `=ISO.CEILING(1,"X")`: "#VALUE!", // LCM "=LCM()": "LCM requires at least 1 argument", "=LCM(-1)": "LCM only accepts positive arguments", "=LCM(1,-1)": "LCM only accepts positive arguments", + `=LCM("X")`: "#VALUE!", // LN - "=LN()": "LN requires 1 numeric argument", + "=LN()": "LN requires 1 numeric argument", + `=LN("X")`: "#VALUE!", // LOG "=LOG()": "LOG requires at least 1 argument", "=LOG(1,2,3)": "LOG allows at most 2 arguments", + `=LOG("X",1)`: "#VALUE!", + `=LOG(1,"X")`: "#VALUE!", "=LOG(0,0)": "#NUM!", "=LOG(1,0)": "#NUM!", "=LOG(1,1)": "#DIV/0!", // LOG10 - "=LOG10()": "LOG10 requires 1 numeric argument", + "=LOG10()": "LOG10 requires 1 numeric argument", + `=LOG10("X")`: "#VALUE!", // MOD - "=MOD()": "MOD requires 2 numeric arguments", - "=MOD(6,0)": "#DIV/0!", + "=MOD()": "MOD requires 2 numeric arguments", + "=MOD(6,0)": "#DIV/0!", + `=MOD("X",0)`: "#VALUE!", + `=MOD(6,"X")`: "#VALUE!", // MROUND - "=MROUND()": "MROUND requires 2 numeric arguments", - "=MROUND(1,0)": "#NUM!", + "=MROUND()": "MROUND requires 2 numeric arguments", + "=MROUND(1,0)": "#NUM!", + "=MROUND(1,-1)": "#NUM!", + `=MROUND("X",0)`: "#VALUE!", + `=MROUND(1,"X")`: "#VALUE!", + // MULTINOMIAL + `=MULTINOMIAL("X")`: "#VALUE!", // _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")`: "#VALUE!", // not support currently // ODD - "=ODD()": "ODD requires 1 numeric argument", + "=ODD()": "ODD requires 1 numeric argument", + `=ODD("X")`: "#VALUE!", // PI "=PI(1)": "PI accepts no arguments", // POWER - "=POWER(0,0)": "#NUM!", - "=POWER(0,-1)": "#DIV/0!", - "=POWER(1)": "POWER requires 2 numeric arguments", + `=POWER("X",1)`: "#VALUE!", + `=POWER(1,"X")`: "#VALUE!", + "=POWER(0,0)": "#NUM!", + "=POWER(0,-1)": "#DIV/0!", + "=POWER(1)": "POWER requires 2 numeric arguments", + // PRODUCT + `=PRODUCT("X")`: "#VALUE!", // QUOTIENT - "=QUOTIENT(1,0)": "#DIV/0!", - "=QUOTIENT(1)": "QUOTIENT requires 2 numeric arguments", + `=QUOTIENT("X",1)`: "#VALUE!", + `=QUOTIENT(1,"X")`: "#VALUE!", + "=QUOTIENT(1,0)": "#DIV/0!", + "=QUOTIENT(1)": "QUOTIENT requires 2 numeric arguments", // RADIANS - "=RADIANS()": "RADIANS requires 1 numeric argument", + `=RADIANS("X")`: "#VALUE!", + "=RADIANS()": "RADIANS requires 1 numeric argument", // RAND "=RAND(1)": "RAND accepts no arguments", // RANDBETWEEN - "=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments", - "=RANDBETWEEN(2,1)": "#NUM!", + `=RANDBETWEEN("X",1)`: "#VALUE!", + `=RANDBETWEEN(1,"X")`: "#VALUE!", + "=RANDBETWEEN()": "RANDBETWEEN requires 2 numeric arguments", + "=RANDBETWEEN(2,1)": "#NUM!", // ROMAN "=ROMAN()": "ROMAN requires at least 1 argument", "=ROMAN(1,2,3)": "ROMAN allows at most 2 arguments", + `=ROMAN("X")`: "#VALUE!", + `=ROMAN("X",1)`: "#VALUE!", // ROUND - "=ROUND()": "ROUND requires 2 numeric arguments", + "=ROUND()": "ROUND requires 2 numeric arguments", + `=ROUND("X",1)`: "#VALUE!", + `=ROUND(1,"X")`: "#VALUE!", // ROUNDDOWN - "=ROUNDDOWN()": "ROUNDDOWN requires 2 numeric arguments", + "=ROUNDDOWN()": "ROUNDDOWN requires 2 numeric arguments", + `=ROUNDDOWN("X",1)`: "#VALUE!", + `=ROUNDDOWN(1,"X")`: "#VALUE!", // ROUNDUP - "=ROUNDUP()": "ROUNDUP requires 2 numeric arguments", + "=ROUNDUP()": "ROUNDUP requires 2 numeric arguments", + `=ROUNDUP("X",1)`: "#VALUE!", + `=ROUNDUP(1,"X")`: "#VALUE!", // SEC - "=_xlfn.SEC()": "SEC requires 1 numeric argument", + "=_xlfn.SEC()": "SEC requires 1 numeric argument", + `=_xlfn.SEC("X")`: "#VALUE!", // _xlfn.SECH - "=_xlfn.SECH()": "SECH requires 1 numeric argument", + "=_xlfn.SECH()": "SECH requires 1 numeric argument", + `=_xlfn.SECH("X")`: "#VALUE!", // SIGN - "=SIGN()": "SIGN requires 1 numeric argument", + "=SIGN()": "SIGN requires 1 numeric argument", + `=SIGN("X")`: "#VALUE!", // SIN - "=SIN()": "SIN requires 1 numeric argument", + "=SIN()": "SIN requires 1 numeric argument", + `=SIN("X")`: "#VALUE!", // SINH - "=SINH()": "SINH requires 1 numeric argument", + "=SINH()": "SINH requires 1 numeric argument", + `=SINH("X")`: "#VALUE!", // SQRT - "=SQRT()": "SQRT requires 1 numeric argument", - "=SQRT(-1)": "#NUM!", + "=SQRT()": "SQRT requires 1 numeric argument", + `=SQRT("X")`: "#VALUE!", + "=SQRT(-1)": "#NUM!", // SQRTPI - "=SQRTPI()": "SQRTPI requires 1 numeric argument", + "=SQRTPI()": "SQRTPI requires 1 numeric argument", + `=SQRTPI("X")`: "#VALUE!", // SUM - "=SUM((": "formula not valid", - "=SUM(-)": "formula not valid", - "=SUM(1+)": "formula not valid", - "=SUM(1-)": "formula not valid", - "=SUM(1*)": "formula not valid", - "=SUM(1/)": "formula not valid", + "=SUM((": "formula not valid", + "=SUM(-)": "formula not valid", + "=SUM(1+)": "formula not valid", + "=SUM(1-)": "formula not valid", + "=SUM(1*)": "formula not valid", + "=SUM(1/)": "formula not valid", + `=SUM("X")`: "#VALUE!", + // SUMSQ + `=SUMSQ("X")`: "#VALUE!", // TAN - "=TAN()": "TAN requires 1 numeric argument", + "=TAN()": "TAN requires 1 numeric argument", + `=TAN("X")`: "#VALUE!", // TANH - "=TANH()": "TANH requires 1 numeric argument", + "=TANH()": "TANH requires 1 numeric argument", + `=TANH("X")`: "#VALUE!", // TRUNC - "=TRUNC()": "TRUNC requires at least 1 argument", + "=TRUNC()": "TRUNC requires at least 1 argument", + `=TRUNC("X")`: "#VALUE!", + `=TRUNC(1,"X")`: "#VALUE!", } for formula, expected := range mathCalcError { f := prepareData() @@ -570,6 +686,17 @@ func TestCalcCellValue(t *testing.T) { assert.Equal(t, "", result, formula) } + volatileFuncs := []string{ + "=RAND()", + "=RANDBETWEEN(1,2)", + } + for _, formula := range volatileFuncs { + f := prepareData() + assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula)) + _, err := f.CalcCellValue("Sheet1", "C1") + assert.NoError(t, err) + } + // Test get calculated cell value on not formula cell. f := prepareData() result, err := f.CalcCellValue("Sheet1", "A1") diff --git a/go.mod b/go.mod index e411f19543d4aefe98cb3d1d4f49559ff359805f..f94f33beb248c52801aacfe8304d60672e124922 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,14 @@ go 1.12 require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/stretchr/testify v1.3.0 + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/stretchr/testify v1.5.1 github.com/xuri/efp v0.0.0-20191019043341-b7dc4fe9aa91 - golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a - golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 + golang.org/x/image v0.0.0-20200430140353-33d19683fad8 + golang.org/x/net v0.0.0-20200506145744-7e3656a0809f golang.org/x/text v0.3.2 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index ff969f082b32a930266a3d87907a1615ed2ec7df..7fa49fe5013be50a0185a8bcad8e7e2ad4f9aefe 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,39 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/xuri/efp v0.0.0-20191019043341-b7dc4fe9aa91 h1:gp02YctZuIPTk0t7qI+wvg3VQwTPyNmSGG6ZqOsjSL8= github.com/xuri/efp v0.0.0-20191019043341-b7dc4fe9aa91/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=