diff --git a/calc.go b/calc.go index 4d2bdcc..e3e7c4d 100644 --- a/calc.go +++ b/calc.go @@ -294,11 +294,15 @@ var tokenPriority = map[string]int{ // IF // IFERROR // IMABS +// IMAGINARY +// IMARGUMENT +// IMCONJUGATE // IMCOS // IMCOSH // IMCOT // IMCSC // IMCSCH +// IMDIV // IMEXP // IMLN // IMLOG10 @@ -1712,13 +1716,61 @@ func (fn *formulaFuncs) IMABS(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "IMABS requires 1 argument") } - inumber, err := strconv.ParseComplex(strings.Replace(argsList.Front().Value.(formulaArg).Value(), "j", "i", -1), 128) + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) if err != nil { return newErrorFormulaArg(formulaErrorNUM, err.Error()) } return newNumberFormulaArg(cmplx.Abs(inumber)) } +// IMAGINARY function returns the imaginary coefficient of a supplied complex +// number. The syntax of the function is: +// +// IMAGINARY(inumber) +// +func (fn *formulaFuncs) IMAGINARY(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMAGINARY requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newNumberFormulaArg(imag(inumber)) +} + +// IMARGUMENT function returns the phase (also called the argument) of a +// supplied complex number. The syntax of the function is: +// +// IMARGUMENT(inumber) +// +func (fn *formulaFuncs) IMARGUMENT(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMARGUMENT requires 1 argument") + } + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + return newNumberFormulaArg(cmplx.Phase(inumber)) +} + +// IMCONJUGATE function returns the complex conjugate of a supplied complex +// number. The syntax of the function is: +// +// IMCONJUGATE(inumber) +// +func (fn *formulaFuncs) IMCONJUGATE(argsList *list.List) formulaArg { + if argsList.Len() != 1 { + return newErrorFormulaArg(formulaErrorVALUE, "IMCONJUGATE 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.Conj(inumber)), "i")) +} + // IMCOS function returns the cosine of a supplied complex number. The syntax // of the function is: // @@ -1728,7 +1780,7 @@ func (fn *formulaFuncs) IMCOS(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "IMCOS requires 1 argument") } - inumber, err := strconv.ParseComplex(strings.Replace(argsList.Front().Value.(formulaArg).Value(), "j", "i", -1), 128) + inumber, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) if err != nil { return newErrorFormulaArg(formulaErrorNUM, err.Error()) } @@ -1807,6 +1859,30 @@ func (fn *formulaFuncs) IMCSCH(argsList *list.List) formulaArg { return newStringFormulaArg(cmplx2str(fmt.Sprint(num), "i")) } +// IMDIV function calculates the quotient of two complex numbers (i.e. divides +// one complex number by another). The syntax of the function is: +// +// IMDIV(inumber1,inumber2) +// +func (fn *formulaFuncs) IMDIV(argsList *list.List) formulaArg { + if argsList.Len() != 2 { + return newErrorFormulaArg(formulaErrorVALUE, "IMDIV requires 2 arguments") + } + inumber1, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + inumber2, err := strconv.ParseComplex(str2cmplx(argsList.Back().Value.(formulaArg).Value()), 128) + if err != nil { + return newErrorFormulaArg(formulaErrorNUM, err.Error()) + } + num := inumber1 / inumber2 + if cmplx.IsInf(num) { + return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM) + } + return newStringFormulaArg(cmplx2str(fmt.Sprint(num), "i")) +} + // IMEXP function returns the exponential of a supplied complex number. The // syntax of the function is: // diff --git a/calc_test.go b/calc_test.go index afbf880..26f8875 100644 --- a/calc_test.go +++ b/calc_test.go @@ -134,6 +134,22 @@ func TestCalcCellValue(t *testing.T) { "=IMABS(\"2j\")": "2", "=IMABS(\"-1+2i\")": "2.23606797749979", "=IMABS(COMPLEX(-1,2,\"j\"))": "2.23606797749979", + // IMAGINARY + "=IMAGINARY(\"5+2i\")": "2", + "=IMAGINARY(\"2-i\")": "-1", + "=IMAGINARY(6)": "0", + "=IMAGINARY(\"3i\")": "3", + "=IMAGINARY(\"4+i\")": "1", + // IMARGUMENT + "=IMARGUMENT(\"5+2i\")": "0.380506377112365", + "=IMARGUMENT(\"2-i\")": "-0.463647609000806", + "=IMARGUMENT(6)": "0", + // IMCONJUGATE + "=IMCONJUGATE(\"5+2i\")": "5-2i", + "=IMCONJUGATE(\"2-i\")": "2+i", + "=IMCONJUGATE(6)": "6", + "=IMCONJUGATE(\"3i\")": "-3i", + "=IMCONJUGATE(\"4+i\")": "4-i", // IMCOS "=IMCOS(0)": "1", "=IMCOS(0.5)": "0.877582561890373", @@ -152,6 +168,10 @@ func TestCalcCellValue(t *testing.T) { "=IMCSC(\"j\")": "-0.8509181282393216i", // IMCSCH "=IMCSCH(COMPLEX(1,-1))": "0.30393100162842646+0.6215180171704284i", + // IMDIV + "=IMDIV(\"5+2i\",\"1+i\")": "3.5-1.5i", + "=IMDIV(\"2+2i\",\"2+i\")": "1.2+0.4i", + "=IMDIV(COMPLEX(5,2),COMPLEX(0,1))": "2-5i", // IMEXP "=IMEXP(0)": "1", "=IMEXP(0.5)": "1.648721270700128", @@ -1241,6 +1261,15 @@ func TestCalcCellValue(t *testing.T) { // IMABS "=IMABS()": "IMABS requires 1 argument", "=IMABS(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMAGINARY + "=IMAGINARY()": "IMAGINARY requires 1 argument", + "=IMAGINARY(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMARGUMENT + "=IMARGUMENT()": "IMARGUMENT requires 1 argument", + "=IMARGUMENT(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + // IMCONJUGATE + "=IMCONJUGATE()": "IMCONJUGATE requires 1 argument", + "=IMCONJUGATE(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", // IMCOS "=IMCOS()": "IMCOS requires 1 argument", "=IMCOS(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", @@ -1258,6 +1287,11 @@ func TestCalcCellValue(t *testing.T) { "=IMCSCH()": "IMCSCH requires 1 argument", "=IMCSCH(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", "=IMCSCH(0)": "#NUM!", + // IMDIV + "=IMDIV()": "IMDIV requires 2 arguments", + "=IMDIV(0,\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", + "=IMDIV(\"\",0)": "strconv.ParseComplex: parsing \"\": invalid syntax", + "=IMDIV(1,0)": "#NUM!", // IMEXP "=IMEXP()": "IMEXP requires 1 argument", "=IMEXP(\"\")": "strconv.ParseComplex: parsing \"\": invalid syntax", diff --git a/lib.go b/lib.go index 0c1938a..26d402a 100644 --- a/lib.go +++ b/lib.go @@ -52,6 +52,9 @@ func (f *File) readXML(name string) []byte { if content, ok := f.XLSX[name]; ok { return content } + if content, ok := f.streams[name]; ok { + return content.rawData.buf.Bytes() + } return []byte{} }