fpspreadsheet: Support cell ranges in calculation of rpn formulas. Tune fpfunc unit. Update test cases.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3272 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-07-03 15:38:15 +00:00
parent 4741c857a8
commit 359ddca7b8
5 changed files with 910 additions and 481 deletions

View File

@ -10,8 +10,8 @@
<IsPartOfProject Value="True"/>
<UnitName Value="test_formula_func"/>
<IsVisibleTab Value="True"/>
<TopLine Value="65"/>
<CursorPos X="47" Y="97"/>
<TopLine Value="33"/>
<CursorPos X="14" Y="47"/>
<UsageCount Value="20"/>
<Loaded Value="True"/>
</Unit0>
@ -28,8 +28,8 @@
<Filename Value="..\..\fpsfunc.pas"/>
<UnitName Value="fpsfunc"/>
<EditorIndex Value="2"/>
<TopLine Value="24"/>
<CursorPos Y="50"/>
<TopLine Value="1594"/>
<CursorPos X="35" Y="1603"/>
<UsageCount Value="10"/>
<Loaded Value="True"/>
</Unit2>
@ -45,124 +45,124 @@
</Units>
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2988" TopLine="2960"/>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="856" TopLine="836"/>
</Position1>
<Position2>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2987" TopLine="2960"/>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="858" TopLine="836"/>
</Position2>
<Position3>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="853" TopLine="836"/>
<Caret Line="860" TopLine="836"/>
</Position3>
<Position4>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="854" TopLine="836"/>
<Caret Line="861" TopLine="836"/>
</Position4>
<Position5>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="855" TopLine="836"/>
<Caret Line="863" TopLine="836"/>
</Position5>
<Position6>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="856" TopLine="836"/>
<Caret Line="864" TopLine="836"/>
</Position6>
<Position7>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="858" TopLine="836"/>
<Caret Line="865" TopLine="836"/>
</Position7>
<Position8>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="860" TopLine="836"/>
<Caret Line="867" TopLine="837"/>
</Position8>
<Position9>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="861" TopLine="836"/>
<Caret Line="875" TopLine="857"/>
</Position9>
<Position10>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="863" TopLine="836"/>
<Caret Line="876" TopLine="857"/>
</Position10>
<Position11>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="864" TopLine="836"/>
<Caret Line="879" TopLine="857"/>
</Position11>
<Position12>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="865" TopLine="836"/>
<Caret Line="876" TopLine="857"/>
</Position12>
<Position13>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="867" TopLine="837"/>
<Caret Line="879" TopLine="857"/>
</Position13>
<Position14>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="875" TopLine="857"/>
<Caret Line="877" TopLine="857"/>
</Position14>
<Position15>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="876" TopLine="857"/>
<Caret Line="879" TopLine="857"/>
</Position15>
<Position16>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
<Caret Line="878" TopLine="857"/>
</Position16>
<Position17>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="876" TopLine="857"/>
<Caret Line="879" TopLine="857"/>
</Position17>
<Position18>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
<Caret Line="878" TopLine="857"/>
</Position18>
<Position19>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="877" TopLine="857"/>
<Caret Line="879" TopLine="857"/>
</Position19>
<Position20>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
<Caret Line="876" TopLine="857"/>
</Position20>
<Position21>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="878" TopLine="857"/>
<Caret Line="879" TopLine="857"/>
</Position21>
<Position22>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
<Caret Line="894" TopLine="876"/>
</Position22>
<Position23>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="878" TopLine="857"/>
</Position23>
<Position24>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
</Position24>
<Position25>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="876" TopLine="857"/>
</Position25>
<Position26>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="879" TopLine="857"/>
</Position26>
<Position27>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="894" TopLine="876"/>
</Position27>
<Position28>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2997" TopLine="2966"/>
</Position28>
<Position29>
</Position23>
<Position24>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2998" TopLine="2967"/>
</Position29>
<Position30>
</Position24>
<Position25>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2961" TopLine="2942"/>
</Position25>
<Position26>
<Filename Value="..\..\fpsfunc.pas"/>
<Caret Line="50" TopLine="24"/>
</Position26>
<Position27>
<Filename Value="..\..\fpsfunc.pas"/>
<Caret Line="1607" Column="52" TopLine="1591"/>
</Position27>
<Position28>
<Filename Value="..\..\fpsfunc.pas"/>
<Caret Line="1606" Column="16" TopLine="1592"/>
</Position28>
<Position29>
<Filename Value="..\..\fpsfunc.pas"/>
<Caret Line="1610" Column="8" TopLine="1593"/>
</Position29>
<Position30>
<Filename Value="test_formula_func.pas"/>
<Caret Line="61" Column="24" TopLine="39"/>
</Position30>
</JumpHistory>
</ProjectSession>

View File

@ -44,24 +44,20 @@ end;
function fpsFV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
arg_interestRate, arg_numberPayments, arg_Payment, arg_PV, arg_paymentType: TsArgument;
data: TsArgNumberArray;
begin
// Pop the argument off the stack.
// Note: they come off in the reverse order they were pushed!
arg_paymentType := Args.Pop;
arg_PV := Args.Pop;
arg_Payment := Args.Pop;
arg_numberPayments := Args.Pop;
arg_interestRate := Args.Pop;
// Call our FV function with the NumberValues of the arguments.
Result := CreateNumber(FV(
arg_interestRate.NumberValue,
arg_numberPayments.NumberValue,
arg_Payment.NumberValue,
arg_PV.NumberValue,
round(arg_paymentType.NumberValue)
));
// Pop the argument off the stack. This can be done by means of PopNumberValues
// which brings the values back into the right order and reports an error
// in case of non-numerical values.
if Args.PopNumberValues(NumArgs, false, data, Result) then
// Call our FV function with the NumberValues of the arguments.
Result := CreateNumber(FV(
data[0], // interest rate
data[1], // number of payments
data[2], // payment
data[3], // present value
round(data[4]) // payment type
));
end;
const
@ -119,6 +115,7 @@ begin
nil))))))));
workbook.WriteToFile('test_fv.xls', sfExcel8, true);
finally
workbook.Free;
end;

File diff suppressed because it is too large Load Diff

View File

@ -1496,6 +1496,7 @@ var
val: TsArgument;
fe: TsFormulaElement;
cell: PCell;
r,c: Cardinal;
begin
if (Length(ACell^.RPNFormulaValue) = 0) or
(ACell^.ContentType = cctError)
@ -1516,9 +1517,21 @@ begin
csNotCalculated: CalcRPNFormula(cell);
csCalculating : raise Exception.Create(lpCircularReference);
end;
args.PushCell(cell);
args.PushCell(cell, self);
end;
fekCellRange:
begin
for r := fe.Row to fe.Row2 do
for c := fe.Col to fe.Col2 do begin
cell := FindCell(r, c);
if cell <> nil then
case cell^.CalcState of
csNotCalculated: CalcRPNFormula(cell);
csCalculating : raise Exception.Create(lpCircularReference);
end;
end;
args.PushCellRange(fe.Row, fe.Col, fe.Row2, fe.Col2, self);
end;
fekCellRange: ;
fekNum:
args.PushNumber(fe.DoubleValue);
fekInteger:

View File

@ -6,6 +6,7 @@
{------------------------------------------------------------------------------}
// Addition
Row := 0;
MyWorksheet.WriteUTF8Text(Row, 0, '=1+1');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
@ -13,6 +14,9 @@
RPNFunc(fekAdd, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(1.0+1.0); // B1 = 2
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// DO NOT CHANGE THIS FORMULA - ITS RESULT (2) IS HARD-CODED IN OTHER TESTS !
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Subtraction
inc(Row);
@ -22,7 +26,10 @@
RPNNumber(10,
RPNFunc(fekSub, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(1-10); // B2 = -9
sollValues[Row] := CreateNumber(1-10); // B2 = -9
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// DO NOT CHANGE THIS FORMULA - ITS RESULT (-9) IS HARD-CODED IN OTHER TESTS !
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Add cell values - relative addresses
inc(Row);
@ -78,6 +85,16 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(10*(-3));
// Multiplication of cell values
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=B1*B2');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNCellValue('B2',
RPNFunc(fekMul, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(2*(-9));
// Division
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=10/200');
@ -98,6 +115,16 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateError(errDivideByZero);
// Division of cell values
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=B1/B2');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNcellValue('B2',
RPNFunc(fekDiv, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(2/(-9));
// Percentage
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=10%');
@ -107,9 +134,18 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(10*0.01);
// Percentage of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=B1%');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekPercent, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(2*0.01);
// Power
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=power(2.0, 0.5)');
MyWorksheet.WriteUTF8Text(Row, 0, '=power(2.0,0.5)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(2.0,
RPNNumber(0.5,
@ -117,6 +153,16 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(power(2, 0.5));
// Power of cell values
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=power(B1,B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNCellValue('B2',
RPNFunc(fekPower, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(power(2, -9));
{$IFDEF ENABLE_CALC_RPN_EXCEPTIONS}
// Power: Error case "power( (negative number), (fractional number) )"
inc(Row);
@ -139,6 +185,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(1);
// Unary minus of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=-B1');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekUMinus, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(-(2));
// Unary plus
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=+(-1)');
@ -149,6 +204,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(-1);
// Unary plus of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=+(B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellvalue('B2',
RPNFunc(fekUPlus, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(+(-9));
// String result
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '="Hallo"');
@ -593,7 +657,7 @@
RPNMissingArg(
RPNFunc(fekLOG, 2, nil)))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(logn(10, 0.1));
sollValues[Row] := CreateError(errOverflow);
// LOG - valid result (1 argument)
inc(Row);
@ -624,6 +688,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateError(errOverflow);
// LOG of cell
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=log(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekLOG, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(logn(10, 2));
// PI
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=pi()');
@ -641,6 +714,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(degtorad(60));
// RADIANS of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=radians(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekRADIANS, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(degtorad(2));
// RAND
// Test omitted because we cannot enforce getting the same random number back
// when we are reading the file.
@ -664,6 +746,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sign(-0.1));
// SIGN of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sign(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekSIGN, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sign(2));
// SIN
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sin(0.1)');
@ -673,6 +764,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sin(0.1));
// SIN of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sin(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekSIN, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sin(2));
// SINH
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sinh(0.1)');
@ -682,6 +782,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sinh(0.1));
// SINH of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sinh(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekSINH, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sinh(2));
// SQRT - valid result
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sqrt(0.1)');
@ -700,6 +809,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateError(errOverflow);
// SQRT of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=sqrt(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellvalue('B1',
RPNFunc(fekSQRT, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(sqrt(2));
// TAN - valid result
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=tan(0.1)');
@ -712,6 +830,15 @@
// TAN - error (argument = pi/2)
// This test is omitted because it is difficult to exactly hit pi/2.
// TAN of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=tan(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekTAN, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(tan(2));
// TANH
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=tanh(0.1)');
@ -721,6 +848,15 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(tanh(0.1));
// TANH of cell value
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=tanh(B1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellValue('B1',
RPNFunc(fekTANH, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(tanh(2));
{------------------------------------------------------------------------------}
{ Date/time functions }
@ -975,7 +1111,16 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(mean([1.0, 1.1, 1.2, 0.9, 0.8]));
// COUNT (no missing values)
// AVERAGE of cell block
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=AVERAGE(B1:B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellRange('B1:B2',
RPNFunc(fekAVERAGE, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(mean([2.0, -9.0]));
// COUNT
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
@ -988,20 +1133,34 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(5);
// COUNT (with missing values)
// COUNT of cell range (no empty cells)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(1, , 1.2, , 0.8)');
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(B1:B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNMissingArg(
RPNNumber(1.2,
RPNMissingArg(
RPNNumber(0.8,
RPNFunc(fekCOUNT, 5, nil))))))));
RPNCellrange('B1:B2',
RPNFunc(fekCOUNT, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(3);
sollValues[Row] := CreateNumber(2);
// MAX
// COUNT of cell range (no empty cells, but with non-numeric cells)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(A1:B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellrange('A1:B2',
RPNFunc(fekCOUNT, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(2);
// COUNT of cell range (with empty cells)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(B1:C2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellrange('B1:C2',
RPNFunc(fekCOUNT, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(2);
// MAX
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
@ -1014,20 +1173,25 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MaxValue([1.0, 1.1, 1.2, 0.9, 0.8]));
// MAX (with missing values)
// MAX of cell range (no empty cells)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(1, , , 0.9, 0.8)');
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(B1:B2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNMissingArg(
RPNMissingArg(
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekMAX, 5, nil))))))));
RPNCellRange('B1:B2',
RPNFunc(fekMAX, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MaxValue([1.0, {1.1, 1.2,} 0.9, 0.8]));
sollValues[Row] := CreateNumber(MaxValue([2.0, -9.0]));
// MIN
// MAX of cell range (incl empty cells)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(B1:C2)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellRange('B1:C2',
RPNFunc(fekMAX, 1, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MaxValue([2.0, -9.0]));
// MIN
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MIN(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(