Przeglądaj źródła

Fix hyperbolic cotangent calculation incorrect and unit test

xuri 4 lat temu
rodzic
commit
4ac32278ff
2 zmienionych plików z 162 dodań i 137 usunięć
  1. 96 83
      calc.go
  2. 66 54
      calc_test.go

+ 96 - 83
calc.go

@@ -344,8 +344,7 @@ func newErrorFormulaArg(formulaError, msg string) formulaArg {
 //
 //
 func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error) {
 func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error) {
 	var err error
 	var err error
-	opdStack, optStack, opfStack, opfdStack, opftStack := NewStack(), NewStack(), NewStack(), NewStack(), NewStack()
-	argsList := list.New()
+	opdStack, optStack, opfStack, opfdStack, opftStack, argsStack := NewStack(), NewStack(), NewStack(), NewStack(), NewStack(), NewStack()
 	for i := 0; i < len(tokens); i++ {
 	for i := 0; i < len(tokens); i++ {
 		token := tokens[i]
 		token := tokens[i]
 
 
@@ -359,6 +358,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
 		// function start
 		// function start
 		if token.TType == efp.TokenTypeFunction && token.TSubType == efp.TokenSubTypeStart {
 		if token.TType == efp.TokenTypeFunction && token.TSubType == efp.TokenSubTypeStart {
 			opfStack.Push(token)
 			opfStack.Push(token)
+			argsStack.Push(list.New().Init())
 			continue
 			continue
 		}
 		}
 
 
@@ -396,7 +396,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
 					if result.Type == ArgUnknown {
 					if result.Type == ArgUnknown {
 						return efp.Token{}, errors.New(formulaErrorVALUE)
 						return efp.Token{}, errors.New(formulaErrorVALUE)
 					}
 					}
-					argsList.PushBack(result)
+					argsStack.Peek().(*list.List).PushBack(result)
 					continue
 					continue
 				}
 				}
 			}
 			}
@@ -417,7 +417,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
 					opftStack.Pop()
 					opftStack.Pop()
 				}
 				}
 				if !opfdStack.Empty() {
 				if !opfdStack.Empty() {
-					argsList.PushBack(formulaArg{
+					argsStack.Peek().(*list.List).PushBack(formulaArg{
 						String: opfdStack.Pop().(efp.Token).TValue,
 						String: opfdStack.Pop().(efp.Token).TValue,
 						Type:   ArgString,
 						Type:   ArgString,
 					})
 					})
@@ -431,7 +431,7 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
 
 
 			// current token is text
 			// current token is text
 			if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
 			if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText {
-				argsList.PushBack(formulaArg{
+				argsStack.Peek().(*list.List).PushBack(formulaArg{
 					String: token.TValue,
 					String: token.TValue,
 					Type:   ArgString,
 					Type:   ArgString,
 				})
 				})
@@ -450,26 +450,26 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
 
 
 				// push opfd to args
 				// push opfd to args
 				if opfdStack.Len() > 0 {
 				if opfdStack.Len() > 0 {
-					argsList.PushBack(formulaArg{
+					argsStack.Peek().(*list.List).PushBack(formulaArg{
 						String: opfdStack.Pop().(efp.Token).TValue,
 						String: opfdStack.Pop().(efp.Token).TValue,
 						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(argsList)})
+					[]reflect.Value{reflect.ValueOf(argsStack.Peek().(*list.List))})
 				if arg.Type == ArgError {
 				if arg.Type == ArgError {
 					return efp.Token{}, errors.New(arg.Value())
 					return efp.Token{}, errors.New(arg.Value())
 				}
 				}
-				argsList.Init()
+				argsStack.Pop()
 				opfStack.Pop()
 				opfStack.Pop()
 				if opfStack.Len() > 0 { // still in function stack
 				if opfStack.Len() > 0 { // still in function stack
 					if nextToken.TType == efp.TokenTypeOperatorInfix {
 					if nextToken.TType == efp.TokenTypeOperatorInfix {
 						// mathematics calculate in formula function
 						// mathematics calculate in formula function
 						opfdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
 						opfdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
 					} else {
 					} else {
-						argsList.PushBack(arg)
+						argsStack.Peek().(*list.List).PushBack(arg)
 					}
 					}
 				} else {
 				} else {
 					opdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
 					opdStack.Push(efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
@@ -1220,15 +1220,15 @@ func (fn *formulaFuncs) ATAN2(argsList *list.List) formulaArg {
 	if argsList.Len() != 2 {
 	if argsList.Len() != 2 {
 		return newErrorFormulaArg(formulaErrorVALUE, "ATAN2 requires 2 numeric arguments")
 		return newErrorFormulaArg(formulaErrorVALUE, "ATAN2 requires 2 numeric arguments")
 	}
 	}
-	x, err := strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	x := argsList.Back().Value.(formulaArg).ToNumber()
+	if x.Type == ArgError {
+		return x
 	}
 	}
-	y, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	y := argsList.Front().Value.(formulaArg).ToNumber()
+	if y.Type == ArgError {
+		return y
 	}
 	}
-	return newNumberFormulaArg(math.Atan2(x, y))
+	return newNumberFormulaArg(math.Atan2(x.Number, y.Number))
 }
 }
 
 
 // BASE function converts a number into a supplied base (radix), and returns a
 // BASE function converts a number into a supplied base (radix), and returns a
@@ -1243,16 +1243,17 @@ func (fn *formulaFuncs) BASE(argsList *list.List) formulaArg {
 	if argsList.Len() > 3 {
 	if argsList.Len() > 3 {
 		return newErrorFormulaArg(formulaErrorVALUE, "BASE allows at most 3 arguments")
 		return newErrorFormulaArg(formulaErrorVALUE, "BASE allows at most 3 arguments")
 	}
 	}
-	var number float64
-	var radix, minLength int
+	var minLength int
 	var err error
 	var err error
-	if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	number := argsList.Front().Value.(formulaArg).ToNumber()
+	if number.Type == ArgError {
+		return number
 	}
 	}
-	if radix, err = strconv.Atoi(argsList.Front().Next().Value.(formulaArg).String); err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	radix := argsList.Front().Next().Value.(formulaArg).ToNumber()
+	if radix.Type == ArgError {
+		return radix
 	}
 	}
-	if radix < 2 || radix > 36 {
+	if int(radix.Number) < 2 || int(radix.Number) > 36 {
 		return newErrorFormulaArg(formulaErrorVALUE, "radix must be an integer >= 2 and <= 36")
 		return newErrorFormulaArg(formulaErrorVALUE, "radix must be an integer >= 2 and <= 36")
 	}
 	}
 	if argsList.Len() > 2 {
 	if argsList.Len() > 2 {
@@ -1260,7 +1261,7 @@ func (fn *formulaFuncs) BASE(argsList *list.List) formulaArg {
 			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
 			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
 		}
 		}
 	}
 	}
-	result := strconv.FormatInt(int64(number), radix)
+	result := strconv.FormatInt(int64(number.Number), int(radix.Number))
 	if len(result) < minLength {
 	if len(result) < minLength {
 		result = strings.Repeat("0", minLength-len(result)) + result
 		result = strings.Repeat("0", minLength-len(result)) + result
 	}
 	}
@@ -1280,18 +1281,20 @@ func (fn *formulaFuncs) CEILING(argsList *list.List) formulaArg {
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING allows at most 2 arguments")
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING allows at most 2 arguments")
 	}
 	}
 	number, significance, res := 0.0, 1.0, 0.0
 	number, significance, res := 0.0, 1.0, 0.0
-	var err error
-	number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	n := argsList.Front().Value.(formulaArg).ToNumber()
+	if n.Type == ArgError {
+		return n
 	}
 	}
+	number = n.Number
 	if number < 0 {
 	if number < 0 {
 		significance = -1
 		significance = -1
 	}
 	}
 	if argsList.Len() > 1 {
 	if argsList.Len() > 1 {
-		if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
-			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+		s := argsList.Back().Value.(formulaArg).ToNumber()
+		if s.Type == ArgError {
+			return s
 		}
 		}
+		significance = s.Number
 	}
 	}
 	if significance < 0 && number > 0 {
 	if significance < 0 && number > 0 {
 		return newErrorFormulaArg(formulaErrorVALUE, "negative sig to CEILING invalid")
 		return newErrorFormulaArg(formulaErrorVALUE, "negative sig to CEILING invalid")
@@ -1319,25 +1322,30 @@ func (fn *formulaFuncs) CEILINGMATH(argsList *list.List) formulaArg {
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH allows at most 3 arguments")
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH allows at most 3 arguments")
 	}
 	}
 	number, significance, mode := 0.0, 1.0, 1.0
 	number, significance, mode := 0.0, 1.0, 1.0
-	var err error
-	if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	n := argsList.Front().Value.(formulaArg).ToNumber()
+	if n.Type == ArgError {
+		return n
 	}
 	}
+	number = n.Number
 	if number < 0 {
 	if 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 {
-			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+		s := argsList.Front().Next().Value.(formulaArg).ToNumber()
+		if s.Type == ArgError {
+			return s
 		}
 		}
+		significance = s.Number
 	}
 	}
 	if argsList.Len() == 1 {
 	if argsList.Len() == 1 {
 		return newNumberFormulaArg(math.Ceil(number))
 		return newNumberFormulaArg(math.Ceil(number))
 	}
 	}
 	if argsList.Len() > 2 {
 	if argsList.Len() > 2 {
-		if mode, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
-			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+		m := argsList.Back().Value.(formulaArg).ToNumber()
+		if m.Type == ArgError {
+			return m
 		}
 		}
+		mode = m.Number
 	}
 	}
 	val, res := math.Modf(number / significance)
 	val, res := math.Modf(number / significance)
 	if res != 0 {
 	if res != 0 {
@@ -1364,11 +1372,11 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) formulaArg {
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE allows at most 2 arguments")
 		return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE allows at most 2 arguments")
 	}
 	}
 	number, significance := 0.0, 1.0
 	number, significance := 0.0, 1.0
-	var err error
-	number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	n := argsList.Front().Value.(formulaArg).ToNumber()
+	if n.Type == ArgError {
+		return n
 	}
 	}
+	number = n.Number
 	if number < 0 {
 	if number < 0 {
 		significance = -1
 		significance = -1
 	}
 	}
@@ -1376,13 +1384,14 @@ func (fn *formulaFuncs) CEILINGPRECISE(argsList *list.List) formulaArg {
 		return newNumberFormulaArg(math.Ceil(number))
 		return newNumberFormulaArg(math.Ceil(number))
 	}
 	}
 	if argsList.Len() > 1 {
 	if argsList.Len() > 1 {
-		if significance, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
-			err = errors.New(formulaErrorVALUE)
-			return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+		s := argsList.Back().Value.(formulaArg).ToNumber()
+		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 / significance)
@@ -1404,19 +1413,22 @@ func (fn *formulaFuncs) COMBIN(argsList *list.List) formulaArg {
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires 2 argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires 2 argument")
 	}
 	}
 	number, chosen, val := 0.0, 0.0, 1.0
 	number, chosen, val := 0.0, 0.0, 1.0
-	var err error
-	if number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64); err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	n := argsList.Front().Value.(formulaArg).ToNumber()
+	if n.Type == ArgError {
+		return n
 	}
 	}
-	if chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	number = n.Number
+	c := argsList.Back().Value.(formulaArg).ToNumber()
+	if c.Type == ArgError {
+		return c
 	}
 	}
+	chosen = c.Number
 	number, chosen = math.Trunc(number), math.Trunc(chosen)
 	number, chosen = math.Trunc(number), math.Trunc(chosen)
 	if chosen > number {
 	if chosen > number {
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires number >= number_chosen")
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires number >= number_chosen")
 	}
 	}
 	if chosen == number || chosen == 0 {
 	if chosen == number || chosen == 0 {
-		return newStringFormulaArg("1")
+		return newNumberFormulaArg(1)
 	}
 	}
 	for c := float64(1); c <= chosen; c++ {
 	for c := float64(1); c <= chosen; c++ {
 		val *= (number + 1 - c) / c
 		val *= (number + 1 - c) / c
@@ -1434,21 +1446,22 @@ func (fn *formulaFuncs) COMBINA(argsList *list.List) formulaArg {
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires 2 argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires 2 argument")
 	}
 	}
 	var number, chosen float64
 	var number, chosen float64
-	var err error
-	number, err = strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	n := argsList.Front().Value.(formulaArg).ToNumber()
+	if n.Type == ArgError {
+		return n
 	}
 	}
-	chosen, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	number = n.Number
+	c := argsList.Back().Value.(formulaArg).ToNumber()
+	if c.Type == ArgError {
+		return c
 	}
 	}
+	chosen = c.Number
 	number, chosen = math.Trunc(number), math.Trunc(chosen)
 	number, chosen = math.Trunc(number), math.Trunc(chosen)
 	if number < chosen {
 	if number < chosen {
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires number > number_chosen")
 		return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires number > number_chosen")
 	}
 	}
 	if number == 0 {
 	if number == 0 {
-		return newStringFormulaArg("0")
+		return newNumberFormulaArg(number)
 	}
 	}
 	args := list.New()
 	args := list.New()
 	args.PushBack(formulaArg{
 	args.PushBack(formulaArg{
@@ -1471,11 +1484,11 @@ func (fn *formulaFuncs) COS(argsList *list.List) formulaArg {
 	if argsList.Len() != 1 {
 	if argsList.Len() != 1 {
 		return newErrorFormulaArg(formulaErrorVALUE, "COS requires 1 numeric argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COS requires 1 numeric argument")
 	}
 	}
-	val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	val := argsList.Front().Value.(formulaArg).ToNumber()
+	if val.Type == ArgError {
+		return val
 	}
 	}
-	return newNumberFormulaArg(math.Cos(val))
+	return newNumberFormulaArg(math.Cos(val.Number))
 }
 }
 
 
 // COSH function calculates the hyperbolic cosine (cosh) of a supplied number.
 // COSH function calculates the hyperbolic cosine (cosh) of a supplied number.
@@ -1487,11 +1500,11 @@ func (fn *formulaFuncs) COSH(argsList *list.List) formulaArg {
 	if argsList.Len() != 1 {
 	if argsList.Len() != 1 {
 		return newErrorFormulaArg(formulaErrorVALUE, "COSH requires 1 numeric argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COSH requires 1 numeric argument")
 	}
 	}
-	val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	val := argsList.Front().Value.(formulaArg).ToNumber()
+	if val.Type == ArgError {
+		return val
 	}
 	}
-	return newNumberFormulaArg(math.Cosh(val))
+	return newNumberFormulaArg(math.Cosh(val.Number))
 }
 }
 
 
 // COT function calculates the cotangent of a given angle. The syntax of the
 // COT function calculates the cotangent of a given angle. The syntax of the
@@ -1503,14 +1516,14 @@ func (fn *formulaFuncs) COT(argsList *list.List) formulaArg {
 	if argsList.Len() != 1 {
 	if argsList.Len() != 1 {
 		return newErrorFormulaArg(formulaErrorVALUE, "COT requires 1 numeric argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COT requires 1 numeric argument")
 	}
 	}
-	val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	val := argsList.Front().Value.(formulaArg).ToNumber()
+	if val.Type == ArgError {
+		return val
 	}
 	}
-	if val == 0 {
+	if val.Number == 0 {
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 	}
 	}
-	return newNumberFormulaArg(math.Tan(val))
+	return newNumberFormulaArg(1 / math.Tan(val.Number))
 }
 }
 
 
 // COTH function calculates the hyperbolic cotangent (coth) of a supplied
 // COTH function calculates the hyperbolic cotangent (coth) of a supplied
@@ -1522,14 +1535,14 @@ func (fn *formulaFuncs) COTH(argsList *list.List) formulaArg {
 	if argsList.Len() != 1 {
 	if argsList.Len() != 1 {
 		return newErrorFormulaArg(formulaErrorVALUE, "COTH requires 1 numeric argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "COTH requires 1 numeric argument")
 	}
 	}
-	val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	val := argsList.Front().Value.(formulaArg).ToNumber()
+	if val.Type == ArgError {
+		return val
 	}
 	}
-	if val == 0 {
+	if val.Number == 0 {
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 	}
 	}
-	return newNumberFormulaArg(math.Tanh(val))
+	return newNumberFormulaArg((math.Exp(val.Number) + math.Exp(-val.Number)) / (math.Exp(val.Number) - math.Exp(-val.Number)))
 }
 }
 
 
 // CSC function calculates the cosecant of a given angle. The syntax of the
 // CSC function calculates the cosecant of a given angle. The syntax of the
@@ -1541,14 +1554,14 @@ func (fn *formulaFuncs) CSC(argsList *list.List) formulaArg {
 	if argsList.Len() != 1 {
 	if argsList.Len() != 1 {
 		return newErrorFormulaArg(formulaErrorVALUE, "CSC requires 1 numeric argument")
 		return newErrorFormulaArg(formulaErrorVALUE, "CSC requires 1 numeric argument")
 	}
 	}
-	val, err := strconv.ParseFloat(argsList.Front().Value.(formulaArg).String, 64)
-	if err != nil {
-		return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+	val := argsList.Front().Value.(formulaArg).ToNumber()
+	if val.Type == ArgError {
+		return val
 	}
 	}
-	if val == 0 {
+	if val.Number == 0 {
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 		return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
 	}
 	}
-	return newNumberFormulaArg(1 / math.Sin(val))
+	return newNumberFormulaArg(1 / math.Sin(val.Number))
 }
 }
 
 
 // CSCH function calculates the hyperbolic cosecant (csch) of a supplied
 // CSCH function calculates the hyperbolic cosecant (csch) of a supplied

+ 66 - 54
calc_test.go

@@ -97,72 +97,84 @@ func TestCalcCellValue(t *testing.T) {
 		"=ATANH(0.5)":      "0.549306144334055",
 		"=ATANH(0.5)":      "0.549306144334055",
 		"=ATANH(ATANH(0))": "0",
 		"=ATANH(ATANH(0))": "0",
 		// ATAN2
 		// ATAN2
-		"=ATAN2(1,1)":  "0.785398163397448",
-		"=ATAN2(1,-1)": "-0.785398163397448",
-		"=ATAN2(4,0)":  "0",
+		"=ATAN2(1,1)":          "0.785398163397448",
+		"=ATAN2(1,-1)":         "-0.785398163397448",
+		"=ATAN2(4,0)":          "0",
+		"=ATAN2(4,ATAN2(4,0))": "0",
 		// BASE
 		// BASE
-		"=BASE(12,2)":      "1100",
-		"=BASE(12,2,8)":    "00001100",
-		"=BASE(100000,16)": "186A0",
+		"=BASE(12,2)":          "1100",
+		"=BASE(12,2,8)":        "00001100",
+		"=BASE(100000,16)":     "186A0",
+		"=BASE(BASE(12,2),16)": "44C",
 		// CEILING
 		// CEILING
-		"=CEILING(22.25,0.1)":   "22.3",
-		"=CEILING(22.25,0.5)":   "22.5",
-		"=CEILING(22.25,1)":     "23",
-		"=CEILING(22.25,10)":    "30",
-		"=CEILING(22.25,20)":    "40",
-		"=CEILING(-22.25,-0.1)": "-22.3",
-		"=CEILING(-22.25,-1)":   "-23",
-		"=CEILING(-22.25,-5)":   "-25",
-		"=CEILING(22.25)":       "23",
+		"=CEILING(22.25,0.1)":              "22.3",
+		"=CEILING(22.25,0.5)":              "22.5",
+		"=CEILING(22.25,1)":                "23",
+		"=CEILING(22.25,10)":               "30",
+		"=CEILING(22.25,20)":               "40",
+		"=CEILING(-22.25,-0.1)":            "-22.3",
+		"=CEILING(-22.25,-1)":              "-23",
+		"=CEILING(-22.25,-5)":              "-25",
+		"=CEILING(22.25)":                  "23",
+		"=CEILING(CEILING(22.25,0.1),0.1)": "22.3",
 		// _xlfn.CEILING.MATH
 		// _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)":       "-15",
-		"=_xlfn.CEILING.MATH(-15.25,-5,-1)": "-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.MATH(_xlfn.CEILING.MATH(15.25,1),1)": "16",
 		// _xlfn.CEILING.PRECISE
 		// _xlfn.CEILING.PRECISE
-		"=_xlfn.CEILING.PRECISE(22.25,0.1)": "22.3",
-		"=_xlfn.CEILING.PRECISE(22.25,0.5)": "22.5",
-		"=_xlfn.CEILING.PRECISE(22.25,1)":   "23",
-		"=_xlfn.CEILING.PRECISE(22.25)":     "23",
-		"=_xlfn.CEILING.PRECISE(22.25,10)":  "30",
-		"=_xlfn.CEILING.PRECISE(22.25,0)":   "0",
-		"=_xlfn.CEILING.PRECISE(-22.25,1)":  "-22",
-		"=_xlfn.CEILING.PRECISE(-22.25,-1)": "-22",
-		"=_xlfn.CEILING.PRECISE(-22.25,5)":  "-20",
+		"=_xlfn.CEILING.PRECISE(22.25,0.1)":                          "22.3",
+		"=_xlfn.CEILING.PRECISE(22.25,0.5)":                          "22.5",
+		"=_xlfn.CEILING.PRECISE(22.25,1)":                            "23",
+		"=_xlfn.CEILING.PRECISE(22.25)":                              "23",
+		"=_xlfn.CEILING.PRECISE(22.25,10)":                           "30",
+		"=_xlfn.CEILING.PRECISE(22.25,0)":                            "0",
+		"=_xlfn.CEILING.PRECISE(-22.25,1)":                           "-22",
+		"=_xlfn.CEILING.PRECISE(-22.25,-1)":                          "-22",
+		"=_xlfn.CEILING.PRECISE(-22.25,5)":                           "-20",
+		"=_xlfn.CEILING.PRECISE(_xlfn.CEILING.PRECISE(22.25,0.1),5)": "25",
 		// COMBIN
 		// COMBIN
-		"=COMBIN(6,1)": "6",
-		"=COMBIN(6,2)": "15",
-		"=COMBIN(6,3)": "20",
-		"=COMBIN(6,4)": "15",
-		"=COMBIN(6,5)": "6",
-		"=COMBIN(6,6)": "1",
-		"=COMBIN(0,0)": "1",
+		"=COMBIN(6,1)":           "6",
+		"=COMBIN(6,2)":           "15",
+		"=COMBIN(6,3)":           "20",
+		"=COMBIN(6,4)":           "15",
+		"=COMBIN(6,5)":           "6",
+		"=COMBIN(6,6)":           "1",
+		"=COMBIN(0,0)":           "1",
+		"=COMBIN(6,COMBIN(0,0))": "6",
 		// _xlfn.COMBINA
 		// _xlfn.COMBINA
-		"=_xlfn.COMBINA(6,1)": "6",
-		"=_xlfn.COMBINA(6,2)": "21",
-		"=_xlfn.COMBINA(6,3)": "56",
-		"=_xlfn.COMBINA(6,4)": "126",
-		"=_xlfn.COMBINA(6,5)": "252",
-		"=_xlfn.COMBINA(6,6)": "462",
-		"=_xlfn.COMBINA(0,0)": "0",
+		"=_xlfn.COMBINA(6,1)":                  "6",
+		"=_xlfn.COMBINA(6,2)":                  "21",
+		"=_xlfn.COMBINA(6,3)":                  "56",
+		"=_xlfn.COMBINA(6,4)":                  "126",
+		"=_xlfn.COMBINA(6,5)":                  "252",
+		"=_xlfn.COMBINA(6,6)":                  "462",
+		"=_xlfn.COMBINA(0,0)":                  "0",
+		"=_xlfn.COMBINA(0,_xlfn.COMBINA(0,0))": "0",
 		// COS
 		// COS
 		"=COS(0.785398163)": "0.707106781467586",
 		"=COS(0.785398163)": "0.707106781467586",
 		"=COS(0)":           "1",
 		"=COS(0)":           "1",
+		"=COS(COS(0))":      "0.54030230586814",
 		// COSH
 		// COSH
-		"=COSH(0)":   "1",
-		"=COSH(0.5)": "1.127625965206381",
-		"=COSH(-2)":  "3.762195691083632",
+		"=COSH(0)":       "1",
+		"=COSH(0.5)":     "1.127625965206381",
+		"=COSH(-2)":      "3.762195691083632",
+		"=COSH(COSH(0))": "1.543080634815244",
 		// _xlfn.COT
 		// _xlfn.COT
-		"=_xlfn.COT(0.785398163397448)": "0.999999999999999",
+		"=_xlfn.COT(0.785398163397448)": "1.000000000000001",
+		"=_xlfn.COT(_xlfn.COT(0.45))":   "-0.545473116787229",
 		// _xlfn.COTH
 		// _xlfn.COTH
-		"=_xlfn.COTH(-3.14159265358979)": "-0.99627207622075",
+		"=_xlfn.COTH(-3.14159265358979)": "-1.003741873197322",
+		"=_xlfn.COTH(_xlfn.COTH(1))":     "1.156014018113954",
 		// _xlfn.CSC
 		// _xlfn.CSC
 		"=_xlfn.CSC(-6)":              "3.578899547254406",
 		"=_xlfn.CSC(-6)":              "3.578899547254406",
 		"=_xlfn.CSC(1.5707963267949)": "1",
 		"=_xlfn.CSC(1.5707963267949)": "1",
+		"=_xlfn.CSC(_xlfn.CSC(1))":    "1.077851840310882",
 		// _xlfn.CSCH
 		// _xlfn.CSCH
 		"=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047",
 		"=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047",
 		// _xlfn.DECIMAL
 		// _xlfn.DECIMAL
@@ -558,7 +570,7 @@ func TestCalcCellValue(t *testing.T) {
 		"=BASE(1,2,3,4)": "BASE allows at most 3 arguments",
 		"=BASE(1,2,3,4)": "BASE allows at most 3 arguments",
 		"=BASE(1,1)":     "radix must be an integer >= 2 and <= 36",
 		"=BASE(1,1)":     "radix must be an integer >= 2 and <= 36",
 		`=BASE("X",2)`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		`=BASE("X",2)`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
-		`=BASE(1,"X")`:   "strconv.Atoi: parsing \"X\": invalid syntax",
+		`=BASE(1,"X")`:   "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		`=BASE(1,2,"X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
 		`=BASE(1,2,"X")`: "strconv.Atoi: parsing \"X\": invalid syntax",
 		// CEILING
 		// CEILING
 		"=CEILING()":      "CEILING requires at least 1 argument",
 		"=CEILING()":      "CEILING requires at least 1 argument",
@@ -576,7 +588,7 @@ func TestCalcCellValue(t *testing.T) {
 		"=_xlfn.CEILING.PRECISE()":      "CEILING.PRECISE requires at least 1 argument",
 		"=_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(1,2,3)": "CEILING.PRECISE allows at most 2 arguments",
 		`=_xlfn.CEILING.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		`=_xlfn.CEILING.PRECISE("X",2)`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
-		`=_xlfn.CEILING.PRECISE(1,"X")`: "#VALUE!",
+		`=_xlfn.CEILING.PRECISE(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
 		// COMBIN
 		// COMBIN
 		"=COMBIN()":       "COMBIN requires 2 argument",
 		"=COMBIN()":       "COMBIN requires 2 argument",
 		"=COMBIN(-1,1)":   "COMBIN requires number >= number_chosen",
 		"=COMBIN(-1,1)":   "COMBIN requires number >= number_chosen",
@@ -1009,7 +1021,7 @@ func TestAND(t *testing.T) {
 	})
 	})
 	fn := formulaFuncs{}
 	fn := formulaFuncs{}
 	result := fn.AND(argsList)
 	result := fn.AND(argsList)
-	assert.Equal(t, result.String, "TRUE")
+	assert.Equal(t, result.String, "")
 	assert.Empty(t, result.Error)
 	assert.Empty(t, result.Error)
 }
 }