diff --git a/components/fpspreadsheet/fpsmath.pas b/components/fpspreadsheet/fpsmath.pas
index 1666c521f..193ec07ac 100644
--- a/components/fpspreadsheet/fpsmath.pas
+++ b/components/fpspreadsheet/fpsmath.pas
@@ -64,7 +64,33 @@ function fpsGreaterEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsLess (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsLessEqual (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsNotEqual (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
-
+{ Math }
+function fpsABS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsACOS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsACOSH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsASIN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsASINH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsATAN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsATANH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsCOS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsCOSH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsDEGREES (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsEXP (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsINT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsLN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsLOG (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsLOG10 (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsPI (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsRADIANS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsRAND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsROUND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsSIGN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsSIN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsSINH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsSQRT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsTAN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsTANH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+{ Logic }
function fpsAND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsFALSE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsIF (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
@@ -527,7 +553,6 @@ begin
Result := CreateBool(false);
end;
-
function fpsNotEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
arg1, arg2: TsArgument;
@@ -544,6 +569,265 @@ begin
Result := CreateBool(false);
end;
+
+{ Math functions }
+
+function fpsABS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(abs(data[0]));
+end;
+
+function fpsACOS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if InRange(data[0], -1, +1) then
+ Result := CreateNumber(arccos(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsACOSH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if data[0] >= 1 then
+ Result := CreateNumber(arccosh(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsASIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if InRange(data[0], -1, +1) then
+ Result := CreateNumber(arcsin(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsASINH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(arcsinh(data[0]));
+end;
+
+function fpsATAN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(arctan(data[0]));
+end;
+
+function fpsATANH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if (data[0] > -1) and (data[0] < +1) then
+ Result := CreateNumber(arctanh(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsCOS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(cos(data[0]));
+end;
+
+function fpsCOSH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(cosh(data[0]));
+end;
+
+function fpsDEGREES(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(RadToDeg(data[0]));
+end;
+
+function fpsEXP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(exp(data[0]));
+end;
+
+function fpsINT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(floor(data[0]));
+end;
+
+function fpsLN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if (data[0] > 0) then
+ Result := CreateNumber(ln(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsLOG(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ arg_base, arg_number: TsArgument;
+ data: TFloatArray;
+ base: Double;
+begin
+ base := 10;
+ if NumArgs = 2 then begin
+ arg_base := Args.Pop;
+ if not arg_base.IsMissing then begin
+ if arg_base.ArgumentType <> atNumber then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ base := arg_base.NumberValue;
+ end;
+ end;
+
+ if base < 0 then begin
+ Result := CreateError(errOverflow);
+ exit;
+ end;
+
+ arg_number := Args.Pop;
+ if arg_number.ArgumentType <> atNumber then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+
+ if arg_number.NumberValue > 0 then
+ Result := CreateNumber(logn(base, arg_number.NumberValue))
+ else
+ Result := CreateError(errOverflow);
+end;
+
+function fpsLOG10(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if (data[0] > 0) then
+ Result := CreateNumber(log10(data[0]))
+ else
+ Result := CreateError(errOverflow); // #NUM!
+ end;
+end;
+
+function fpsPI(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+begin
+ Result := CreateNumber(pi);
+end;
+
+function fpsRADIANS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(degtorad(data[0]))
+end;
+
+function fpsRAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+begin
+ Result := CreateNumber(random);
+end;
+
+function fpsROUND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 2, data, Result) then
+ Result := CreateNumber(RoundTo(data[0], round(data[1])))
+end;
+
+function fpsSIGN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(sign(data[0]))
+end;
+
+function fpsSIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(sin(data[0]))
+end;
+
+function fpsSINH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(sinh(data[0]))
+end;
+
+function fpsSQRT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if data[0] >= 0.0 then
+ Result := CreateNumber(sqrt(data[0]))
+ else
+ Result := CreateError(errOverflow);
+ end;
+end;
+
+function fpsTAN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if frac(data[0] / (pi*0.5)) = 0 then
+ Result := CreateError(errOverflow)
+ else
+ Result := CreateNumber(tan(data[0]))
+ end;
+end;
+
+function fpsTANH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then
+ Result := CreateNumber(tanh(data[0]))
+end;
+
+
+{ Logical functions }
+
function fpsAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TBoolArray;
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 2f705d719..c3903e3e1 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -1123,31 +1123,31 @@ const
(Symbol:'<>'; MinParams:2; MaxParams:2; Func:fpsNotEqual), // fekNotEqual
(Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen
{ math }
- (Symbol:'ABS'; MinParams:1; MaxParams:1; Func:nil), // fekABS
- (Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:nil), // fekACOS
- (Symbol:'ACOSH'; MinParams:1; MaxParams:1; Func:nil), // fekACOSH
- (Symbol:'ASIN'; MinParams:1; MaxParams:1; Func:nil), // fekASIN
- (Symbol:'ASINH'; MinParams:1; MaxParams:1; Func:nil), // fekASINH
- (Symbol:'ATAN'; MinParams:1; MaxParams:1; Func:nil), // fekATAN
- (Symbol:'ATANH'; MinParams:1; MaxParams:1; Func:nil), // fekATANH,
- (Symbol:'COS'; MinParams:1; MaxParams:1; Func:nil), // fekCOS
- (Symbol:'COSH'; MinParams:1; MaxParams:1; Func:nil), // fekCOSH
- (Symbol:'DEGREES'; MinParams:1; MaxParams:1; Func:nil), // fekDEGREES
- (Symbol:'EXP'; MinParams:1; MaxParams:1; Func:nil), // fekEXP
- (Symbol:'INT'; MinParams:1; MaxParams:1; Func:nil), // fekINT
- (Symbol:'LN'; MinParams:1; MaxParams:1; Func:nil), // fekLN
- (Symbol:'LOG'; MinParams:1; MaxParams:2; Func:nil), // fekLOG,
- (Symbol:'LOG10'; MinParams:1; MaxParams:1; Func:nil), // fekLOG10
- (Symbol:'PI'; MinParams:0; MaxParams:0; Func:nil), // fekPI
- (Symbol:'RADIANS'; MinParams:1; MaxParams:1; Func:nil), // fekRADIANS
- (Symbol:'RAND'; MinParams:0; MaxParams:0; Func:nil), // fekRAND
- (Symbol:'ROUND'; MinParams:2; MaxParams:2; Func:nil), // fekROUND,
- (Symbol:'SIGN'; MinParams:1; MaxParams:1; Func:nil), // fekSIGN
- (Symbol:'SIN'; MinParams:1; MaxParams:1; Func:nil), // fekSIN
- (Symbol:'SINH'; MinParams:1; MaxParams:1; Func:nil), // fekSINH
- (Symbol:'SQRT'; MinParams:1; MaxParams:1; Func:nil), // fekSQRT,
- (Symbol:'TAN'; MinParams:1; MaxParams:1; Func:nil), // fekTAN
- (Symbol:'TANH'; MinParams:1; MaxParams:1; Func:nil), // fekTANH,
+ (Symbol:'ABS'; MinParams:1; MaxParams:1; Func:fpsABS), // fekABS
+ (Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:fpsACOS), // fekACOS
+ (Symbol:'ACOSH'; MinParams:1; MaxParams:1; Func:fpsACOSH), // fekACOSH
+ (Symbol:'ASIN'; MinParams:1; MaxParams:1; Func:fpsASIN), // fekASIN
+ (Symbol:'ASINH'; MinParams:1; MaxParams:1; Func:fpsASINH), // fekASINH
+ (Symbol:'ATAN'; MinParams:1; MaxParams:1; Func:fpsATAN), // fekATAN
+ (Symbol:'ATANH'; MinParams:1; MaxParams:1; Func:fpsATANH), // fekATANH,
+ (Symbol:'COS'; MinParams:1; MaxParams:1; Func:fpsCOS), // fekCOS
+ (Symbol:'COSH'; MinParams:1; MaxParams:1; Func:fpsCOSH), // fekCOSH
+ (Symbol:'DEGREES'; MinParams:1; MaxParams:1; Func:fpsDEGREES), // fekDEGREES
+ (Symbol:'EXP'; MinParams:1; MaxParams:1; Func:fpsEXP), // fekEXP
+ (Symbol:'INT'; MinParams:1; MaxParams:1; Func:fpsINT), // fekINT
+ (Symbol:'LN'; MinParams:1; MaxParams:1; Func:fpsLN), // fekLN
+ (Symbol:'LOG'; MinParams:1; MaxParams:2; Func:fpsLOG), // fekLOG,
+ (Symbol:'LOG10'; MinParams:1; MaxParams:1; Func:fpsLOG10), // fekLOG10
+ (Symbol:'PI'; MinParams:0; MaxParams:0; Func:fpsPI), // fekPI
+ (Symbol:'RADIANS'; MinParams:1; MaxParams:1; Func:fpsRADIANS), // fekRADIANS
+ (Symbol:'RAND'; MinParams:0; MaxParams:0; Func:fpsRAND), // fekRAND
+ (Symbol:'ROUND'; MinParams:2; MaxParams:2; Func:fpsROUND), // fekROUND,
+ (Symbol:'SIGN'; MinParams:1; MaxParams:1; Func:fpsSIGN), // fekSIGN
+ (Symbol:'SIN'; MinParams:1; MaxParams:1; Func:fpsSIN), // fekSIN
+ (Symbol:'SINH'; MinParams:1; MaxParams:1; Func:fpsSINH), // fekSINH
+ (Symbol:'SQRT'; MinParams:1; MaxParams:1; Func:fpsSQRT), // fekSQRT,
+ (Symbol:'TAN'; MinParams:1; MaxParams:1; Func:fpsTAN), // fekTAN
+ (Symbol:'TANH'; MinParams:1; MaxParams:1; Func:fpsTANH), // fekTANH,
{ date/time }
(Symbol:'DATE'; MinParams:3; MaxParams:3; Func:nil), // fekDATE
(Symbol:'DATEDIF'; MinParams:3; MaxParams:3; Func:nil), // fekDATEDIF
diff --git a/components/fpspreadsheet/tests/formulatests.pas b/components/fpspreadsheet/tests/formulatests.pas
index 0859418bc..c2a6893a5 100644
--- a/components/fpspreadsheet/tests/formulatests.pas
+++ b/components/fpspreadsheet/tests/formulatests.pas
@@ -142,7 +142,7 @@ var
expected: TsArgument;
cell: PCell;
sollValues: array of TsArgument;
- a, b: Double;
+ formula: String;
begin
TempFile := GetTempFileName;
@@ -174,6 +174,7 @@ begin
fail('Error in test code. Failed to get named worksheet');
for Row := 0 to MyWorksheet.GetLastRowIndex do begin
+ formula := MyWorksheet.ReadAsUTF8Text(Row, 0);
cell := MyWorksheet.FindCell(Row, 1);
if (cell = nil) then
fail('Error in test code: Failed to get cell ' + CellNotation(MyWorksheet, Row, 1));
@@ -186,22 +187,27 @@ begin
end;
expected := SollValues[row];
CheckEquals(ord(expected.ArgumentType), ord(actual.ArgumentType),
- 'Test read calculated formula data type mismatch, cell '+CellNotation(MyWorkSheet,Row,1));
+ 'Test read calculated formula data type mismatch, formula "' + formula +
+ '", cell '+CellNotation(MyWorkSheet,Row,1));
case actual.ArgumentType of
atBool:
CheckEquals(BoolToStr(expected.BoolValue), BoolToStr(actual.BoolValue),
- 'Test read calculated formula result mismatch, cell '+CellNotation(MyWorkSheet,Row,1));
+ 'Test read calculated formula result mismatch, formula "' + formula +
+ '", cell '+CellNotation(MyWorkSheet,Row,1));
atNumber:
CheckEquals(expected.NumberValue, actual.NumberValue,
- 'Test read calculated formula result mismatch, cell '+CellNotation(MyWorkSheet,Row,1));
+ 'Test read calculated formula result mismatch, formula "' + formula +
+ '", cell '+CellNotation(MyWorkSheet,Row,1));
atString:
CheckEquals(expected.StringValue, actual.StringValue,
- 'Test read calculated formula result mismatch, cell '+CellNotation(MyWorkSheet,Row,1));
+ 'Test read calculated formula result mismatch, formula "' + formula +
+ '", cell '+CellNotation(MyWorkSheet,Row,1));
atError:
CheckEquals(
GetEnumName(TypeInfo(TsErrorValue), ord(expected.ErrorValue)),
GetEnumname(TypeInfo(TsErrorValue), ord(actual.ErrorValue)),
- 'Test read calculated formula error value mismatch, cell '+CellNotation(MyWorkSheet,Row,1));
+ 'Test read calculated formula error value mismatch, formula ' + formula +
+ ', cell '+CellNotation(MyWorkSheet,Row,1));
end;
end;
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index ad3f18290..f9bb72a93 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -47,6 +47,9 @@
+
+
+
@@ -156,6 +159,9 @@
+
+
+
diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
index d5690456c..6309cab6f 100644
--- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
+++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
@@ -321,6 +321,369 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateBool(1<>1);
+
+
+{------------------------------------------------------------------------------}
+{ Math }
+{------------------------------------------------------------------------------}
+
+ // ABS
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=abs(-1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-1,
+ RPNFunc(fekABS, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(abs(-1));
+
+ // ARCCOS - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=acos(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekACOS, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arccos(0.1));
+
+ // ACOS - error result (arccos is not defined outside the interval [-1..1]
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=acos(-2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-2,
+ RPNFunc(fekACOS, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverFlow);
+
+ // ARCCOSH - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=acosh(1.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.1,
+ RPNFunc(fekACOSH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arccosh(1.1));
+
+ // ACOSH - error result (arccos is not defined below 1
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=acosh(0.9)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.9,
+ RPNFunc(fekACOSH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverFlow);
+
+ // ASIN
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=asin(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekASIN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arcsin(0.1));
+
+ // ASIN - error result (arcsin is not defined outside the interval [-1..1]
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=asin(-2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-2,
+ RPNFunc(fekASIN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverFlow);
+
+ // ARCSINH
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=asinh(1.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.1,
+ RPNFunc(fekASINH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arcsinh(1.1));
+
+ // ATAN
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=atan(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekATAN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arctan(0.1));
+
+ // ATANH - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=atanh(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekATANH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(arctanh(0.1));
+
+ // ATANH - error result (arctan is only defined within ]-1,1[
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=atanh(1.0)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.0,
+ RPNFunc(fekATANH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverFlow);
+
+ // COS
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=cos(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekCOS, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(cos(0.1));
+
+ // COSH
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=cosh(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekCOSH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(cosh(0.1));
+
+ // DEGREES
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=degrees(1.0)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.0,
+ RPNFunc(fekDEGREES, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(radToDeg(1.0));
+
+ // EXP
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=exp(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekEXP, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(exp(0.1));
+
+ // INT (positive argument)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=int(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekINT, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(floor(0.1));
+
+ // INT (negative argument)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=int(-0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNFunc(fekINT, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(floor(-0.1));
+
+ // LN - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=ln(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekLN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(ln(0.1));
+
+ // LN - error due to argument = 0
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=ln(0.0)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.0,
+ RPNFunc(fekLN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // LN - error due to argument < 0
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=ln(-0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNFunc(fekLN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // LOG10 - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log10(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekLOG10, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(log10(0.1));
+
+ // LOG10 - error due to argument = 0
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log10(0.0)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.0,
+ RPNFunc(fekLOG10, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // LOG10 - error due to argument < 0
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log10(-0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNFunc(fekLOG10, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // LOG - valid result (2 arguments)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log(0.1, 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNNumber(2,
+ RPNFunc(fekLOG, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(logn(2, 0.1));
+
+ // LOG - valid result (2 arguments, base missing)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log(0.1, )');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNMissingArg(
+ RPNFunc(fekLOG, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(logn(10, 0.1));
+
+ // LOG - valid result (1 argument)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekLOG, 1, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(logn(10, 0.1));
+
+ // LOG - negative base
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log(0.1, -2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNNumber(-2,
+ RPNFunc(fekLOG, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // LOG - negative value
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=log(-0.1, 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNNumber(2.0,
+ RPNFunc(fekLOG, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // PI
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=pi()');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNFunc(fekPI, nil)));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(pi);
+
+ // RADIANS
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=radians(60)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(60,
+ RPNFunc(fekRADIANS, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(degtorad(60));
+
+ // RAND
+ // Test omitted because we cannot enforce getting the same random number back
+ // when we are reading the file.
+
+ // ROUND
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=ROUND(pi(), 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNFunc(fekPI,
+ RPNNumber(2,
+ RPNFunc(fekROUND, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(RoundTo(pi, 2));
+
+ // SIGN
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=sign(-0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNFunc(fekSIGN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(sign(-0.1));
+
+ // SIN
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=sin(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekSIN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(sin(0.1));
+
+ // SINH
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=sinh(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekSINH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(sinh(0.1));
+
+ // SQRT - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=sqrt(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekSQRT, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(sqrt(0.1));
+
+ // SQRT - error (negative argument)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=sqrt(-0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(-0.1,
+ RPNFunc(fekSQRT, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateError(errOverflow);
+
+ // TAN - valid result
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=tan(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekTAN, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(tan(0.1));
+
+ // TAN - error (argument = pi/2)
+ // This test is omitted because it is difficult to exactly hit pi/2.
+
+ // TANH
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=tanh(0.1)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(0.1,
+ RPNFunc(fekTANH, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(tanh(0.1));
+
+{------------------------------------------------------------------------------}
+{ Logical functions }
+{------------------------------------------------------------------------------}
+
// AND of one values (bool)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=AND(true)');
@@ -490,3 +853,4 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString('A');
+