diff --git a/calc.go b/calc.go index 3098e48..ae22c02 100644 --- a/calc.go +++ b/calc.go @@ -248,6 +248,7 @@ var tokenPriority = map[string]int{ // COLUMNS // COMBIN // COMBINA +// COMPLEX // CONCAT // CONCATENATE // COS @@ -1449,6 +1450,35 @@ func (fn *formulaFuncs) bitwise(name string, argsList *list.List) formulaArg { return newNumberFormulaArg(float64(bitwiseFunc(int(num1.Number), int(num2.Number)))) } +// COMPLEX function takes two arguments, representing the real and the +// imaginary coefficients of a complex number, and from these, creates a +// complex number. The syntax of the function is: +// +// COMPLEX(real_num,i_num,[suffix]) +// +func (fn *formulaFuncs) COMPLEX(argsList *list.List) formulaArg { + if argsList.Len() < 2 { + return newErrorFormulaArg(formulaErrorVALUE, "COMPLEX requires at least 2 arguments") + } + if argsList.Len() > 3 { + return newErrorFormulaArg(formulaErrorVALUE, "COMPLEX allows at most 3 arguments") + } + real, i, suffix := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Front().Next().Value.(formulaArg).ToNumber(), "i" + if real.Type != ArgNumber { + return real + } + if i.Type != ArgNumber { + return i + } + if argsList.Len() == 3 { + if suffix = strings.ToLower(argsList.Back().Value.(formulaArg).Value()); suffix != "i" && suffix != "j" { + return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) + } + } + r := strings.NewReplacer("(", "", ")", "", "0+", "", "+0i", "", "0+0i", "0", "i", suffix) + return newStringFormulaArg(r.Replace(fmt.Sprint(complex(real.Number, i.Number)))) +} + // DEC2BIN function converts a decimal number into a Binary (Base 2) number. // The syntax of the function is: // diff --git a/calc_test.go b/calc_test.go index 04f95bc..2abeec0 100644 --- a/calc_test.go +++ b/calc_test.go @@ -83,6 +83,13 @@ func TestCalcCellValue(t *testing.T) { // BITXOR "=BITXOR(5,6)": "3", "=BITXOR(9,12)": "5", + // COMPLEX + "=COMPLEX(5,2)": "5+2i", + "=COMPLEX(5,-9)": "5-9i", + "=COMPLEX(-1,2,\"j\")": "-1+2j", + "=COMPLEX(10,-5,\"i\")": "10-5i", + "=COMPLEX(0,5)": "5i", + "=COMPLEX(3,0)": "3", // DEC2BIN "=DEC2BIN(2)": "10", "=DEC2BIN(3)": "11", @@ -1080,6 +1087,12 @@ func TestCalcCellValue(t *testing.T) { "=BITXOR(\"\",-1)": "#NUM!", "=BITXOR(1,\"\")": "#NUM!", "=BITXOR(1,2^48)": "#NUM!", + // COMPLEX + "=COMPLEX()": "COMPLEX requires at least 2 arguments", + "=COMPLEX(10,-5,\"\")": "#VALUE!", + "=COMPLEX(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=COMPLEX(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", + "=COMPLEX(10,-5,\"i\",0)": "COMPLEX allows at most 3 arguments", // DEC2BIN "=DEC2BIN()": "DEC2BIN requires at least 1 argument", "=DEC2BIN(1,1,1)": "DEC2BIN allows at most 2 arguments", diff --git a/file.go b/file.go index 8be71c5..ab74645 100644 --- a/file.go +++ b/file.go @@ -131,6 +131,9 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) { } for path, content := range f.XLSX { + if _, ok := f.streams[path]; ok { + continue + } fi, err := zw.Create(path) if err != nil { zw.Close()