From 3345e89b96fa058273da732be48d01cff4f69960 Mon Sep 17 00:00:00 2001 From: xuri Date: Mon, 5 Apr 2021 13:00:34 +0800 Subject: [PATCH] #65 fn: IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN --- calc.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++- calc_test.go | 49 ++++++++++++++++++++++ 2 files changed, 163 insertions(+), 2 deletions(-) diff --git a/calc.go b/calc.go index 9cb67a1..521529f 100644 --- a/calc.go +++ b/calc.go @@ -302,6 +302,12 @@ var tokenPriority = map[string]int{ // IMEXP // IMLN // IMLOG10 +// IMSIN +// IMSINH +// IMSQRT +// IMSUB +// IMSUM +// IMTAN // INT // ISBLANK // ISERR @@ -1490,7 +1496,7 @@ func (fn *formulaFuncs) COMPLEX(argsList *list.List) formulaArg { // cmplx2str replace complex number string characters. func cmplx2str(c, suffix string) string { - if c == "(0+0i)" || c == "(0-0i)" { + if c == "(0+0i)" || c == "(-0+0i)" || c == "(0-0i)" || c == "(-0-0i)" { return "0" } c = strings.TrimPrefix(c, "(") @@ -1504,7 +1510,7 @@ func cmplx2str(c, suffix string) string { c = strings.TrimPrefix(c, "0+") c = strings.TrimSuffix(c, "+0i") c = strings.TrimSuffix(c, "-0i") - c = strings.NewReplacer("+1i", "i", "-1i", "-i").Replace(c) + c = strings.NewReplacer("+1i", "+i", "-1i", "-i").Replace(c) c = strings.Replace(c, "i", suffix, -1) return c } @@ -1851,6 +1857,112 @@ func (fn *formulaFuncs) IMLOG10(argsList *list.List) formulaArg { return newStringFormulaArg(cmplx2str(fmt.Sprint(num), "i")) } +// IMSIN function returns the Sine of a supplied complex number. The syntax of +// the function is: +// +// IMSIN(inumber) +// +func (fn *formulaFuncs) IMSIN(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMSIN requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(cmplx.Sin(inumber)), "i")) +} + +// IMSINH function returns the hyperbolic sine of a supplied complex number. +// The syntax of the function is: +// +// IMSINH(inumber) +// +func (fn *formulaFuncs) IMSINH(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMSINH requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(cmplx.Sinh(inumber)), "i")) +} + +// IMSQRT function returns the square root of a supplied complex number. The +// syntax of the function is: +// +// IMSQRT(inumber) +// +func (fn *formulaFuncs) IMSQRT(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMSQRT requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(cmplx.Sqrt(inumber)), "i")) +} + +// IMSUB function calculates the difference between two complex numbers +// (i.e. subtracts one complex number from another). The syntax of the +// function is: +// +// IMSUB(inumber1,inumber2) +// +func (fn *formulaFuncs) IMSUB(argsList *list.List) formulaArg { + if argsList.Len() != 2 { + return newErrorFormulaArg(formulaErrorVALUE, "IMSUB requires 2 arguments") + } + i1, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + i2, err := strconv.ParseComplex(str2cmplx(argsList.Back().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(i1-i2), "i")) +} + +// IMSUM function calculates the sum of two or more complex numbers. The +// syntax of the function is: +// +// IMSUM(inumber1,inumber2,...) +// +func (fn *formulaFuncs) IMSUM(argsList *list.List) formulaArg { + if argsList.Len() < 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMSUM requires at least 1 argument") + } + var result complex128 + for arg := argsList.Front(); arg != nil; arg = arg.Next() { + token := arg.Value.(formulaArg) + num, err := strconv.ParseComplex(str2cmplx(token.Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + result += num + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(result), "i")) +} + +// IMTAN function returns the tangent of a supplied complex number. The syntax +// of the function is: +// +// IMTAN(inumber) +// +func (fn *formulaFuncs) IMTAN(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMTAN requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(cmplx.Tan(inumber)), "i")) +} + // OCT2BIN function converts an Octal (Base 8) number into a Binary (Base 2) // number. The syntax of the function is: // diff --git a/calc_test.go b/calc_test.go index 5fbc6a3..590432d 100644 --- a/calc_test.go +++ b/calc_test.go @@ -167,6 +167,36 @@ func TestCalcCellValue(t *testing.T) { "=IMLOG10(\"3+0.5i\")": "0.48307086636951624+0.07172315929479262i", "=IMLOG10(\"2-i\")": "0.34948500216800943-0.20135959813668655i", "=IMLOG10(COMPLEX(1,-1))": "0.1505149978319906-0.3410940884604603i", + // IMSIN + "=IMSIN(0.5)": "0.479425538604203", + "=IMSIN(\"3+0.5i\")": "0.15913058529843999-0.5158804424525267i", + "=IMSIN(\"2-i\")": "1.4031192506220405+0.4890562590412937i", + "=IMSIN(COMPLEX(1,-1))": "1.2984575814159773-0.6349639147847361i", + // IMSINH + "=IMSINH(-0)": "0", + "=IMSINH(0.5)": "0.521095305493747", + "=IMSINH(\"3+0.5i\")": "8.791512343493714+4.82669427481082i", + "=IMSINH(\"2-i\")": "1.9596010414216063-3.165778513216168i", + "=IMSINH(COMPLEX(1,-1))": "0.6349639147847361-1.2984575814159773i", + // IMSQRT + "=IMSQRT(\"i\")": "0.7071067811865476+0.7071067811865476i", + "=IMSQRT(\"2-i\")": "1.455346690225355-0.34356074972251244i", + "=IMSQRT(\"5+2i\")": "2.27872385417085+0.4388421169022545i", + "=IMSQRT(6)": "2.449489742783178", + "=IMSQRT(\"-2-4i\")": "1.1117859405028423-1.7989074399478673i", + // IMSUB + "=IMSUB(\"5+i\",\"1+4i\")": "4-3i", + "=IMSUB(\"9+2i\",6)": "3+2i", + "=IMSUB(COMPLEX(5,2),COMPLEX(0,1))": "5+i", + // IMSUM + "=IMSUM(\"1-i\",\"5+10i\",2)": "8+9i", + "=IMSUM(COMPLEX(5,2),COMPLEX(0,1))": "5+3i", + // IMTAN + "=IMTAN(-0)": "0", + "=IMTAN(0.5)": "0.546302489843791", + "=IMTAN(\"3+0.5i\")": "-0.11162105077158344+0.46946999342588536i", + "=IMTAN(\"2-i\")": "-0.24345820118572523-1.16673625724092i", + "=IMTAN(COMPLEX(1,-1))": "0.2717525853195117-1.0839233273386948i", // OCT2BIN "=OCT2BIN(\"5\")": "101", "=OCT2BIN(\"0000000001\")": "1", @@ -1206,6 +1236,25 @@ func TestCalcCellValue(t *testing.T) { "=IMLOG10()": "IMLOG10 requires 1 argument", "=IMLOG10(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", "=IMLOG10(0)": "#NUM!", + // IMSIN + "=IMSIN()": "IMSIN requires 1 argument", + "=IMSIN(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMSINH + "=IMSINH()": "IMSINH requires 1 argument", + "=IMSINH(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMSQRT + "=IMSQRT()": "IMSQRT requires 1 argument", + "=IMSQRT(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMSUB + "=IMSUB()": "IMSUB requires 2 arguments", + "=IMSUB(0,\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + "=IMSUB(\"\",0)": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMSUM + "=IMSUM()": "IMSUM requires at least 1 argument", + "=IMSUM(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMTAN + "=IMTAN()": "IMTAN requires 1 argument", + "=IMTAN(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", // OCT2BIN "=OCT2BIN()": "OCT2BIN requires at least 1 argument", "=OCT2BIN(1,1,1)": "OCT2BIN allows at most 2 arguments",