mirror of
https://github.com/unidoc/unioffice.git
synced 2025-05-08 19:29:25 +08:00
formula: support for more math/trig formulas
- EVEN - EXP - FACT - FACTDOUBLE - FLOOR.MATH - FLOOR.PRECISE - GCD - INT - ISO.CEILING - LCM - LN - LOG - LOG10
This commit is contained in:
parent
341c2ef03e
commit
e0786dae4a
@ -41,6 +41,20 @@ func init() {
|
|||||||
//RegisterFunction("CSCH"
|
//RegisterFunction("CSCH"
|
||||||
RegisterFunction("_xlfn.DECIMAL", Decimal)
|
RegisterFunction("_xlfn.DECIMAL", Decimal)
|
||||||
RegisterFunction("DEGREES", Degrees)
|
RegisterFunction("DEGREES", Degrees)
|
||||||
|
RegisterFunction("EVEN", Even)
|
||||||
|
RegisterFunction("EXP", makeMathWrapper("EXP", math.Exp))
|
||||||
|
RegisterFunction("FACT", Fact)
|
||||||
|
RegisterFunction("FACTDOUBLE", FactDouble)
|
||||||
|
//RegisterFunction("FLOOR", )
|
||||||
|
RegisterFunction("_xlfn.FLOOR.MATH", FloorMath)
|
||||||
|
RegisterFunction("_xlfn.FLOOR.PRECISE", FloorPrecise)
|
||||||
|
RegisterFunction("GCD", GCD)
|
||||||
|
RegisterFunction("INT", Int)
|
||||||
|
RegisterFunction("ISO.CEILING", CeilingPrecise) // appears to be the same from what I can tell
|
||||||
|
RegisterFunction("LCM", LCM)
|
||||||
|
RegisterFunction("LN", makeMathWrapper("LN", math.Log))
|
||||||
|
RegisterFunction("LOG", Log)
|
||||||
|
RegisterFunction("LOG10", makeMathWrapper("LOG10", math.Log10))
|
||||||
RegisterFunction("PI", Pi)
|
RegisterFunction("PI", Pi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +70,12 @@ func makeMathWrapper(name string, fn func(x float64) float64) Function {
|
|||||||
switch arg.Type {
|
switch arg.Type {
|
||||||
case ResultTypeNumber:
|
case ResultTypeNumber:
|
||||||
v := fn(arg.ValueNumber)
|
v := fn(arg.ValueNumber)
|
||||||
if v != v {
|
if math.IsNaN(v) {
|
||||||
return MakeErrorResult(name + " returned NaN")
|
return MakeErrorResult(name + " returned NaN")
|
||||||
}
|
}
|
||||||
|
if math.IsInf(v, 0) {
|
||||||
|
return MakeErrorResult(name + " returned infinity")
|
||||||
|
}
|
||||||
return MakeNumberResult(v)
|
return MakeNumberResult(v)
|
||||||
case ResultTypeList, ResultTypeString:
|
case ResultTypeList, ResultTypeString:
|
||||||
return MakeErrorResult(name + " requires a numeric argument")
|
return MakeErrorResult(name + " requires a numeric argument")
|
||||||
@ -169,7 +186,7 @@ func CeilingMath(args []Result) Result {
|
|||||||
// number to round
|
// number to round
|
||||||
number := args[0].AsNumber()
|
number := args[0].AsNumber()
|
||||||
if number.Type != ResultTypeNumber {
|
if number.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("first arugment to CEILING.MATH() must be a number")
|
return MakeErrorResult("first argument to CEILING.MATH() must be a number")
|
||||||
}
|
}
|
||||||
|
|
||||||
// significance
|
// significance
|
||||||
@ -180,7 +197,7 @@ func CeilingMath(args []Result) Result {
|
|||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
sigArg := args[1].AsNumber()
|
sigArg := args[1].AsNumber()
|
||||||
if sigArg.Type != ResultTypeNumber {
|
if sigArg.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("second arugment to CEILING.MATH() must be a number")
|
return MakeErrorResult("second argument to CEILING.MATH() must be a number")
|
||||||
}
|
}
|
||||||
significance = sigArg.ValueNumber
|
significance = sigArg.ValueNumber
|
||||||
}
|
}
|
||||||
@ -190,7 +207,7 @@ func CeilingMath(args []Result) Result {
|
|||||||
if len(args) > 2 {
|
if len(args) > 2 {
|
||||||
dirArg := args[2].AsNumber()
|
dirArg := args[2].AsNumber()
|
||||||
if dirArg.Type != ResultTypeNumber {
|
if dirArg.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("third arugment to CEILING.MATH() must be a number")
|
return MakeErrorResult("third argument to CEILING.MATH() must be a number")
|
||||||
}
|
}
|
||||||
direction = dirArg.ValueNumber
|
direction = dirArg.ValueNumber
|
||||||
}
|
}
|
||||||
@ -211,6 +228,8 @@ func CeilingMath(args []Result) Result {
|
|||||||
return MakeNumberResult(v * significance)
|
return MakeNumberResult(v * significance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CeilingPrecise is an implementation of the CEILING.PRECISE function which
|
||||||
|
// returns the ceiling of a number.
|
||||||
func CeilingPrecise(args []Result) Result {
|
func CeilingPrecise(args []Result) Result {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return MakeErrorResult("CEILING.PRECISE() requires at least one argument")
|
return MakeErrorResult("CEILING.PRECISE() requires at least one argument")
|
||||||
@ -221,7 +240,7 @@ func CeilingPrecise(args []Result) Result {
|
|||||||
// number to round
|
// number to round
|
||||||
number := args[0].AsNumber()
|
number := args[0].AsNumber()
|
||||||
if number.Type != ResultTypeNumber {
|
if number.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("first arugment to CEILING.PRECISE() must be a number")
|
return MakeErrorResult("first argument to CEILING.PRECISE() must be a number")
|
||||||
}
|
}
|
||||||
|
|
||||||
// significance
|
// significance
|
||||||
@ -232,7 +251,7 @@ func CeilingPrecise(args []Result) Result {
|
|||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
sigArg := args[1].AsNumber()
|
sigArg := args[1].AsNumber()
|
||||||
if sigArg.Type != ResultTypeNumber {
|
if sigArg.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("second arugment to CEILING.MATH() must be a number")
|
return MakeErrorResult("second argument to CEILING.MATH() must be a number")
|
||||||
}
|
}
|
||||||
// don't care about sign of significance
|
// don't care about sign of significance
|
||||||
significance = math.Abs(sigArg.ValueNumber)
|
significance = math.Abs(sigArg.ValueNumber)
|
||||||
@ -265,12 +284,12 @@ func Base(args []Result) Result {
|
|||||||
// number to convert
|
// number to convert
|
||||||
number := args[0].AsNumber()
|
number := args[0].AsNumber()
|
||||||
if number.Type != ResultTypeNumber {
|
if number.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("first arugment to BASE() must be a number")
|
return MakeErrorResult("first argument to BASE() must be a number")
|
||||||
}
|
}
|
||||||
|
|
||||||
radixArg := args[1].AsNumber()
|
radixArg := args[1].AsNumber()
|
||||||
if radixArg.Type != ResultTypeNumber {
|
if radixArg.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("second arugment to BASE() must be a number")
|
return MakeErrorResult("second argument to BASE() must be a number")
|
||||||
}
|
}
|
||||||
radix := int(radixArg.ValueNumber)
|
radix := int(radixArg.ValueNumber)
|
||||||
if radix < 0 || radix > 36 {
|
if radix < 0 || radix > 36 {
|
||||||
@ -282,7 +301,7 @@ func Base(args []Result) Result {
|
|||||||
if len(args) > 2 {
|
if len(args) > 2 {
|
||||||
lenArg := args[2].AsNumber()
|
lenArg := args[2].AsNumber()
|
||||||
if lenArg.Type != ResultTypeNumber {
|
if lenArg.Type != ResultTypeNumber {
|
||||||
return MakeErrorResult("third arugment to BASE() must be a number")
|
return MakeErrorResult("third argument to BASE() must be a number")
|
||||||
}
|
}
|
||||||
minLength = int(lenArg.ValueNumber)
|
minLength = int(lenArg.ValueNumber)
|
||||||
}
|
}
|
||||||
@ -346,14 +365,6 @@ func Combina(args []Result) Result {
|
|||||||
return Combin(args)
|
return Combin(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fact(f float64) float64 {
|
|
||||||
res := float64(1)
|
|
||||||
for i := float64(2); i <= f; i++ {
|
|
||||||
res *= i
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decimal is an implementation of the Excel function DECIMAL() that parses a string
|
// Decimal is an implementation of the Excel function DECIMAL() that parses a string
|
||||||
// in a given base and returns the numeric result.
|
// in a given base and returns the numeric result.
|
||||||
func Decimal(args []Result) Result {
|
func Decimal(args []Result) Result {
|
||||||
@ -394,6 +405,337 @@ func Degrees(args []Result) Result {
|
|||||||
return MakeNumberResult(180.0 / math.Pi * vArg.ValueNumber)
|
return MakeNumberResult(180.0 / math.Pi * vArg.ValueNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Even is an implementation of the Excel EVEN() that rounds a number to the
|
||||||
|
// nearest even integer.
|
||||||
|
func Even(args []Result) Result {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return MakeErrorResult("EVEN() requires one argument")
|
||||||
|
}
|
||||||
|
vArg := args[0].AsNumber()
|
||||||
|
if vArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("EVEN() requires number argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
sign := math.Signbit(vArg.ValueNumber)
|
||||||
|
m, r := math.Modf(vArg.ValueNumber / 2)
|
||||||
|
v := m * 2
|
||||||
|
if r != 0 {
|
||||||
|
if !sign {
|
||||||
|
v += 2
|
||||||
|
} else {
|
||||||
|
v -= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MakeNumberResult(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fact(f float64) float64 {
|
||||||
|
res := float64(1)
|
||||||
|
for i := float64(2); i <= f; i++ {
|
||||||
|
res *= i
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fact is an implementation of the excel FACT function which returns the
|
||||||
|
// factorial of a positive numeric input.
|
||||||
|
func Fact(args []Result) Result {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return MakeErrorResult("FACT() accepts a single numeric argument")
|
||||||
|
}
|
||||||
|
vArg := args[0].AsNumber()
|
||||||
|
if vArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("FACT() accepts a single numeric argument")
|
||||||
|
}
|
||||||
|
if vArg.ValueNumber < 0 {
|
||||||
|
return MakeErrorResult("FACT() accepts only positive arguments")
|
||||||
|
}
|
||||||
|
return MakeNumberResult(fact(vArg.ValueNumber))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FactDouble is an implementation of the excel FACTDOUBLE function which
|
||||||
|
// returns the double factorial of a positive numeric input.
|
||||||
|
func FactDouble(args []Result) Result {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return MakeErrorResult("FACTDOUBLE() accepts a single numeric argument")
|
||||||
|
}
|
||||||
|
vArg := args[0].AsNumber()
|
||||||
|
if vArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("FACTDOUBLE() accepts a single numeric argument")
|
||||||
|
}
|
||||||
|
if vArg.ValueNumber < 0 {
|
||||||
|
return MakeErrorResult("FACTDOUBLE() accepts only positive arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := float64(1)
|
||||||
|
v := math.Trunc(vArg.ValueNumber)
|
||||||
|
for i := v; i > 1; i -= 2 {
|
||||||
|
res *= i
|
||||||
|
}
|
||||||
|
return MakeNumberResult(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloorMath implements _xlfn.FLOOR.MATH which rounds numbers down to the
|
||||||
|
// nearest multiple of the second argument, toward or away from zero as
|
||||||
|
// specified by the third argument.
|
||||||
|
func FloorMath(args []Result) Result {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return MakeErrorResult("FLOOR.MATH() requires at least one argument")
|
||||||
|
}
|
||||||
|
if len(args) > 3 {
|
||||||
|
return MakeErrorResult("FLOOR.MATH() allows at most three arguments")
|
||||||
|
}
|
||||||
|
// number to round
|
||||||
|
number := args[0].AsNumber()
|
||||||
|
if number.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("first argument to FLOOR.MATH() must be a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
// significance
|
||||||
|
significance := float64(1)
|
||||||
|
if number.ValueNumber < 0 {
|
||||||
|
significance = -1
|
||||||
|
}
|
||||||
|
if len(args) > 1 {
|
||||||
|
sigArg := args[1].AsNumber()
|
||||||
|
if sigArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("second argument to FLOOR.MATH() must be a number")
|
||||||
|
}
|
||||||
|
significance = sigArg.ValueNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// round direction
|
||||||
|
direction := float64(1)
|
||||||
|
if len(args) > 2 {
|
||||||
|
dirArg := args[2].AsNumber()
|
||||||
|
if dirArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("third argument to FLOOR.MATH() must be a number")
|
||||||
|
}
|
||||||
|
direction = dirArg.ValueNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) == 1 {
|
||||||
|
return MakeNumberResult(math.Floor(number.ValueNumber))
|
||||||
|
}
|
||||||
|
|
||||||
|
v := number.ValueNumber
|
||||||
|
v, res := math.Modf(v / significance)
|
||||||
|
if res != 0 && number.ValueNumber < 0 && direction > 0 {
|
||||||
|
v++
|
||||||
|
}
|
||||||
|
return MakeNumberResult(v * significance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloorPrecise is an implementation of the FlOOR.PRECISE function.
|
||||||
|
func FloorPrecise(args []Result) Result {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return MakeErrorResult("FLOOR.PRECISE() requires at least one argument")
|
||||||
|
}
|
||||||
|
if len(args) > 2 {
|
||||||
|
return MakeErrorResult("FLOOR.PRECISE() allows at most two arguments")
|
||||||
|
}
|
||||||
|
// number to round
|
||||||
|
number := args[0].AsNumber()
|
||||||
|
if number.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("first argument to FLOOR.PRECISE() must be a number")
|
||||||
|
}
|
||||||
|
|
||||||
|
// significance
|
||||||
|
significance := float64(1)
|
||||||
|
if number.ValueNumber < 0 {
|
||||||
|
significance = -1
|
||||||
|
}
|
||||||
|
if len(args) > 1 {
|
||||||
|
sigArg := args[1].AsNumber()
|
||||||
|
if sigArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("second argument to FLOOR.MATH() must be a number")
|
||||||
|
}
|
||||||
|
// don't care about sign of significance
|
||||||
|
significance = math.Abs(sigArg.ValueNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) == 1 {
|
||||||
|
return MakeNumberResult(math.Floor(number.ValueNumber))
|
||||||
|
}
|
||||||
|
|
||||||
|
v := number.ValueNumber
|
||||||
|
v, res := math.Modf(v / significance)
|
||||||
|
if res != 0 {
|
||||||
|
if number.ValueNumber < 0 {
|
||||||
|
v--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MakeNumberResult(v * significance)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gcd(a, b float64) float64 {
|
||||||
|
a = math.Trunc(a)
|
||||||
|
b = math.Trunc(b)
|
||||||
|
if a == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if b == 0 {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
for a != b {
|
||||||
|
if a > b {
|
||||||
|
a = a - b
|
||||||
|
} else {
|
||||||
|
b = b - a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCD implements the Excel GCD() function which returns the greatest common
|
||||||
|
// divisor of a range of numbers.
|
||||||
|
func GCD(args []Result) Result {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return MakeErrorResult("GCD() requires at least one argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
numbers := []float64{}
|
||||||
|
for _, arg := range args {
|
||||||
|
switch arg.Type {
|
||||||
|
case ResultTypeString:
|
||||||
|
na := arg.AsNumber()
|
||||||
|
if na.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("GCD() only accepts numeric arguments")
|
||||||
|
}
|
||||||
|
numbers = append(numbers, na.ValueNumber)
|
||||||
|
case ResultTypeList:
|
||||||
|
res := GCD(arg.ValueList)
|
||||||
|
if res.Type != ResultTypeNumber {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
numbers = append(numbers, res.ValueNumber)
|
||||||
|
case ResultTypeNumber:
|
||||||
|
numbers = append(numbers, arg.ValueNumber)
|
||||||
|
case ResultTypeError:
|
||||||
|
return arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if numbers[0] < 0 {
|
||||||
|
return MakeErrorResult("GCD() only accepts positive arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(numbers) == 1 {
|
||||||
|
return MakeNumberResult(numbers[0])
|
||||||
|
}
|
||||||
|
res := numbers[0]
|
||||||
|
for i := 1; i < len(numbers); i++ {
|
||||||
|
if numbers[i] < 0 {
|
||||||
|
return MakeErrorResult("GCD() only accepts positive arguments")
|
||||||
|
}
|
||||||
|
res = gcd(res, numbers[i])
|
||||||
|
}
|
||||||
|
return MakeNumberResult(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lcm(a, b float64) float64 {
|
||||||
|
a = math.Trunc(a)
|
||||||
|
b = math.Trunc(b)
|
||||||
|
if a == 0 && b == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return a * b / gcd(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCM implements the Excel LCM() function which returns the least common
|
||||||
|
// multiple of a range of numbers.
|
||||||
|
func LCM(args []Result) Result {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return MakeErrorResult("LCM() requires at least one argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
numbers := []float64{}
|
||||||
|
for _, arg := range args {
|
||||||
|
switch arg.Type {
|
||||||
|
case ResultTypeString:
|
||||||
|
na := arg.AsNumber()
|
||||||
|
if na.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("LCM() only accepts numeric arguments")
|
||||||
|
}
|
||||||
|
numbers = append(numbers, na.ValueNumber)
|
||||||
|
case ResultTypeList:
|
||||||
|
res := LCM(arg.ValueList)
|
||||||
|
if res.Type != ResultTypeNumber {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
numbers = append(numbers, res.ValueNumber)
|
||||||
|
case ResultTypeNumber:
|
||||||
|
numbers = append(numbers, arg.ValueNumber)
|
||||||
|
case ResultTypeError:
|
||||||
|
return arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if numbers[0] < 0 {
|
||||||
|
return MakeErrorResult("LCM() only accepts positive arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(numbers) == 1 {
|
||||||
|
return MakeNumberResult(numbers[0])
|
||||||
|
}
|
||||||
|
res := numbers[0]
|
||||||
|
for i := 1; i < len(numbers); i++ {
|
||||||
|
if numbers[i] < 0 {
|
||||||
|
return MakeErrorResult("LCM() only accepts positive arguments")
|
||||||
|
}
|
||||||
|
res = lcm(res, numbers[i])
|
||||||
|
}
|
||||||
|
return MakeNumberResult(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int is an implementation of the Excel INT() function that rounds a number
|
||||||
|
// down to an integer.
|
||||||
|
func Int(args []Result) Result {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return MakeErrorResult("INT() requires a single numeric argument")
|
||||||
|
}
|
||||||
|
nArg := args[0].AsNumber()
|
||||||
|
if nArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("INT() requires a single numeric argument")
|
||||||
|
}
|
||||||
|
trunc, rem := math.Modf(nArg.ValueNumber)
|
||||||
|
if rem < 0 {
|
||||||
|
trunc--
|
||||||
|
}
|
||||||
|
return MakeNumberResult(trunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log implements the Excel LOG function which returns the log of a number. By
|
||||||
|
// default the result is base 10, however the second argument to the function
|
||||||
|
// can specify a different base.
|
||||||
|
func Log(args []Result) Result {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return MakeErrorResult("LOG() requires at least one numeric argument")
|
||||||
|
}
|
||||||
|
if len(args) > 2 {
|
||||||
|
return MakeErrorResult("LOG() accepts a maximum of two arguments")
|
||||||
|
}
|
||||||
|
nArg := args[0].AsNumber()
|
||||||
|
if nArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("LOG() requires at least one numeric argument")
|
||||||
|
}
|
||||||
|
base := 10.0
|
||||||
|
if len(args) > 1 {
|
||||||
|
bArg := args[1].AsNumber()
|
||||||
|
if bArg.Type != ResultTypeNumber {
|
||||||
|
return MakeErrorResult("LOG() requires second argument to be numeric")
|
||||||
|
}
|
||||||
|
base = args[1].ValueNumber
|
||||||
|
}
|
||||||
|
if nArg.ValueNumber == 0 {
|
||||||
|
return MakeErrorResult("LOG() requires first argument to be non-zero")
|
||||||
|
}
|
||||||
|
if base == 0 {
|
||||||
|
return MakeErrorResult("LOG() requires second argument to be non-zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
return MakeNumberResult(math.Log(nArg.ValueNumber) / math.Log(base))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Pi is an implementation of the Excel Pi() function that just returns the Pi
|
// Pi is an implementation of the Excel Pi() function that just returns the Pi
|
||||||
// constant.
|
// constant.
|
||||||
func Pi(args []Result) Result {
|
func Pi(args []Result) Result {
|
||||||
|
@ -596,8 +596,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch data[p] {
|
switch data[p] {
|
||||||
case 36:
|
case 36:
|
||||||
goto tr61
|
goto tr61
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 123:
|
case 123:
|
||||||
goto tr55
|
goto tr55
|
||||||
case 125:
|
case 125:
|
||||||
@ -606,9 +606,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -620,7 +620,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -630,35 +630,35 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch data[p] {
|
switch data[p] {
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr74
|
goto tr72
|
||||||
case 123:
|
case 123:
|
||||||
goto tr74
|
goto tr55
|
||||||
case 125:
|
case 125:
|
||||||
goto tr74
|
goto tr55
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case data[p] < 48:
|
case data[p] < 48:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 35:
|
case data[p] > 35:
|
||||||
if 37 <= data[p] && data[p] <= 45 {
|
if 37 <= data[p] && data[p] <= 47 {
|
||||||
goto tr74
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr74
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] > 57:
|
case data[p] > 57:
|
||||||
switch {
|
switch {
|
||||||
case data[p] < 65:
|
case data[p] < 65:
|
||||||
if 58 <= data[p] && data[p] <= 63 {
|
if 58 <= data[p] && data[p] <= 63 {
|
||||||
goto tr74
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] > 90:
|
case data[p] > 90:
|
||||||
if 91 <= data[p] && data[p] <= 95 {
|
if 91 <= data[p] && data[p] <= 95 {
|
||||||
goto tr74
|
goto tr55
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr76
|
goto tr72
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr72
|
goto tr72
|
||||||
@ -668,38 +668,38 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch data[p] {
|
switch data[p] {
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 123:
|
case 123:
|
||||||
goto tr55
|
goto tr76
|
||||||
case 125:
|
case 125:
|
||||||
goto tr55
|
goto tr76
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case data[p] < 48:
|
case data[p] < 48:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 35:
|
case data[p] > 35:
|
||||||
if 37 <= data[p] && data[p] <= 45 {
|
if 37 <= data[p] && data[p] <= 47 {
|
||||||
goto tr55
|
goto tr76
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr76
|
||||||
}
|
}
|
||||||
case data[p] > 57:
|
case data[p] > 57:
|
||||||
switch {
|
switch {
|
||||||
case data[p] < 65:
|
case data[p] < 65:
|
||||||
if 58 <= data[p] && data[p] <= 63 {
|
if 58 <= data[p] && data[p] <= 63 {
|
||||||
goto tr55
|
goto tr76
|
||||||
}
|
}
|
||||||
case data[p] > 90:
|
case data[p] > 90:
|
||||||
if 91 <= data[p] && data[p] <= 95 {
|
if 91 <= data[p] && data[p] <= 95 {
|
||||||
goto tr55
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
goto tr76
|
goto tr76
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr76
|
goto tr72
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto tr73
|
||||||
}
|
}
|
||||||
goto tr31
|
goto tr31
|
||||||
case 43:
|
case 43:
|
||||||
@ -708,8 +708,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr0
|
goto tr72
|
||||||
case 123:
|
case 123:
|
||||||
goto tr0
|
goto tr0
|
||||||
case 125:
|
case 125:
|
||||||
@ -718,9 +718,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr0
|
goto tr0
|
||||||
@ -732,7 +732,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr0
|
goto tr0
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr0
|
goto tr0
|
||||||
@ -742,8 +742,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch data[p] {
|
switch data[p] {
|
||||||
case 36:
|
case 36:
|
||||||
goto tr61
|
goto tr61
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 65:
|
case 65:
|
||||||
goto tr77
|
goto tr77
|
||||||
case 123:
|
case 123:
|
||||||
@ -754,9 +754,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -768,7 +768,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 66:
|
case data[p] >= 66:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -780,8 +780,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 76:
|
case 76:
|
||||||
goto tr78
|
goto tr78
|
||||||
case 123:
|
case 123:
|
||||||
@ -792,9 +792,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -806,7 +806,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -818,8 +818,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 83:
|
case 83:
|
||||||
goto tr79
|
goto tr79
|
||||||
case 123:
|
case 123:
|
||||||
@ -830,9 +830,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -844,7 +844,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -856,8 +856,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 69:
|
case 69:
|
||||||
goto tr80
|
goto tr80
|
||||||
case 123:
|
case 123:
|
||||||
@ -868,9 +868,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -882,7 +882,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -892,8 +892,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch data[p] {
|
switch data[p] {
|
||||||
case 36:
|
case 36:
|
||||||
goto tr61
|
goto tr61
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 79:
|
case 79:
|
||||||
goto tr81
|
goto tr81
|
||||||
case 82:
|
case 82:
|
||||||
@ -906,9 +906,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -920,7 +920,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -932,8 +932,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 68:
|
case 68:
|
||||||
goto tr83
|
goto tr83
|
||||||
case 123:
|
case 123:
|
||||||
@ -944,9 +944,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -958,7 +958,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -970,8 +970,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 79:
|
case 79:
|
||||||
goto tr84
|
goto tr84
|
||||||
case 123:
|
case 123:
|
||||||
@ -982,9 +982,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -996,7 +996,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -1008,8 +1008,8 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr61
|
goto tr61
|
||||||
case 40:
|
case 40:
|
||||||
goto tr75
|
goto tr75
|
||||||
case 47:
|
case 46:
|
||||||
goto tr55
|
goto tr72
|
||||||
case 85:
|
case 85:
|
||||||
goto tr79
|
goto tr79
|
||||||
case 123:
|
case 123:
|
||||||
@ -1020,9 +1020,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
switch {
|
switch {
|
||||||
case data[p] < 58:
|
case data[p] < 58:
|
||||||
switch {
|
switch {
|
||||||
case data[p] > 45:
|
case data[p] > 47:
|
||||||
if 48 <= data[p] && data[p] <= 57 {
|
if 48 <= data[p] && data[p] <= 57 {
|
||||||
goto tr72
|
goto tr73
|
||||||
}
|
}
|
||||||
case data[p] >= 34:
|
case data[p] >= 34:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -1034,7 +1034,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
goto tr55
|
goto tr55
|
||||||
}
|
}
|
||||||
case data[p] >= 65:
|
case data[p] >= 65:
|
||||||
goto tr73
|
goto tr74
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
goto tr55
|
goto tr55
|
||||||
@ -1295,10 +1295,10 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
tr71:
|
tr71:
|
||||||
cs = 27
|
cs = 27
|
||||||
goto f32
|
goto f32
|
||||||
tr74:
|
tr75:
|
||||||
cs = 27
|
cs = 27
|
||||||
goto f33
|
goto f33
|
||||||
tr75:
|
tr76:
|
||||||
cs = 27
|
cs = 27
|
||||||
goto f34
|
goto f34
|
||||||
tr85:
|
tr85:
|
||||||
@ -1352,10 +1352,10 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
tr72:
|
tr72:
|
||||||
cs = 41
|
cs = 41
|
||||||
goto _again
|
goto _again
|
||||||
tr76:
|
tr73:
|
||||||
cs = 42
|
cs = 42
|
||||||
goto _again
|
goto _again
|
||||||
tr73:
|
tr74:
|
||||||
cs = 43
|
cs = 43
|
||||||
goto f24
|
goto f24
|
||||||
tr80:
|
tr80:
|
||||||
@ -1401,7 +1401,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
f4:
|
f4:
|
||||||
_acts = 7
|
_acts = 7
|
||||||
goto execFuncs
|
goto execFuncs
|
||||||
f34:
|
f33:
|
||||||
_acts = 9
|
_acts = 9
|
||||||
goto execFuncs
|
goto execFuncs
|
||||||
f5:
|
f5:
|
||||||
@ -1458,7 +1458,7 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
f27:
|
f27:
|
||||||
_acts = 45
|
_acts = 45
|
||||||
goto execFuncs
|
goto execFuncs
|
||||||
f33:
|
f34:
|
||||||
_acts = 47
|
_acts = 47
|
||||||
goto execFuncs
|
goto execFuncs
|
||||||
f25:
|
f25:
|
||||||
@ -1858,9 +1858,9 @@ func (l *Lexer) lex(r io.Reader) {
|
|||||||
case 40:
|
case 40:
|
||||||
goto tr55
|
goto tr55
|
||||||
case 41:
|
case 41:
|
||||||
goto tr74
|
|
||||||
case 42:
|
|
||||||
goto tr55
|
goto tr55
|
||||||
|
case 42:
|
||||||
|
goto tr76
|
||||||
case 43:
|
case 43:
|
||||||
goto tr0
|
goto tr0
|
||||||
case 44:
|
case 44:
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
horizontalRange = '$'? [0-9]+ ':' '$'? [0-9]+;
|
horizontalRange = '$'? [0-9]+ ':' '$'? [0-9]+;
|
||||||
|
|
||||||
# there is a function list at https://msdn.microsoft.com/en-us/library/dd906358(v=office.12).aspx
|
# there is a function list at https://msdn.microsoft.com/en-us/library/dd906358(v=office.12).aspx
|
||||||
builtinFunction = [A-Z] [A-Z0-9]+ '(';
|
builtinFunction = [A-Z] [A-Z0-9.]+ '(';
|
||||||
excelFn = '_xlfn.' [A-Z_] [A-Z0-9.]+ '(';
|
excelFn = '_xlfn.' [A-Z_] [A-Z0-9.]+ '(';
|
||||||
|
|
||||||
sheetChar = ^['%\[\]\\:/?();{}#"=<>&+\-*/^%,_];
|
sheetChar = ^['%\[\]\\:/?();{}#"=<>&+\-*/^%,_];
|
||||||
|
BIN
spreadsheet/formula/testdata/formulareference.xlsx
vendored
BIN
spreadsheet/formula/testdata/formulareference.xlsx
vendored
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user