fpspreadsheet: Calculate most statistical and some string functions in rpn formulas. Beginning to handle missing arguments correctly.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3256 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-06-30 15:49:49 +00:00
parent c2a5a2dd5d
commit 57036aa680
3 changed files with 487 additions and 87 deletions

View File

@ -33,10 +33,6 @@ type
procedure Delete(AIndex: Integer);
end;
procedure FixMissingBool (var Arg: TsArgument; ABool: Boolean);
procedure FixMissingNumber(var Arg: TsArgument; ANumber: Double);
procedure FixMissingString(var Arg: TsArgument; AString: String);
function CreateBool(AValue: Boolean): TsArgument;
function CreateNumber(AValue: Double): TsArgument;
function CreateString(AValue: String): TsArgument;
@ -90,13 +86,30 @@ 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 }
{ Statistical functions }
function fpsAVEDEV (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsAVERAGE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsMAX (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsMIN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsPRODUCT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsSTDEV (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsSTDEVP (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsSUM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsSUMSQ (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsVAR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsVARP (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ Logical functions }
function fpsAND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsFALSE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsIF (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsNOT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsOR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsTRUE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ String functions }
function fpsLOWER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsTRIM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsUPPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
implementation
@ -104,9 +117,9 @@ uses
Math;
type
TBoolArray = array of boolean;
TBoolArray = array of boolean;
TFloatArray = array of double;
TStrArray = array of string;
TStrArray = array of string;
{ TsArgumentStack }
@ -194,39 +207,6 @@ begin
end;
{ Missing arguments }
{@@
Replaces a missing boolean argument by the passed boolean value
@param Arg Argument to be considered
@param ABool Replacement for the missing value
}
procedure FixMissingBool(var Arg: TsArgument; ABool: Boolean);
begin
if Arg.IsMissing then Arg.BoolValue := ABool;
end;
{@@
Replaces a missing number argument by the passed number value
@param Arg Argument to be considered
@param ANumber Replacement for the missing value
}
procedure FixMissingNumber(var Arg: TsArgument; ANumber: Double);
begin
if Arg.IsMissing then Arg.NumberValue := ANumber;
end;
{@@
Replaces a missing string argument by the passed string value
@param Arg Argument to be considered
@param AString Replacement for the missing value
}
procedure FixMissingString(var Arg: TsArgument; AString: String);
begin
if Arg.IsMissing then Arg.StringValue := AString;
end;
{ Preparing arguments }
function GetBoolFromArgument(Arg: TsArgument; var AValue: Boolean): TsErrorValue;
@ -265,29 +245,34 @@ function CreateBool(AValue: Boolean): TsArgument;
begin
Result.ArgumentType := atBool;
Result.Boolvalue := AValue;
Result.IsMissing := false;
end;
function CreateNumber(AValue: Double): TsArgument;
begin
Result.ArgumentType := atNumber;
Result.NumberValue := AValue;
Result.IsMissing := false;
end;
function CreateString(AValue: String): TsArgument;
begin
Result.ArgumentType := atString;
Result.StringValue := AValue;
Result.IsMissing := false;
end;
function CreateError(AError: TsErrorValue): TsArgument;
begin
Result.ArgumentType := atError;
Result.ErrorValue := AError;
Result.IsMissing := false;
end;
function CreateEmpty: TsArgument;
begin
Result.ArgumentType := atEmpty;
Result.IsMissing := false;
end;
{@@
@ -298,29 +283,47 @@ end;
@param AValues (output) Array containing the retrieved boolean values.
The array length is given by NumArgs. The data in the array
are in the same order in which they were pushed onto the stack.
Missing arguments are not included in the array, the case
of missing arguments must be handled separately if the are
important.
@param AErrArg (output) Argument containing an error code, e.g. errWrongType
if non-boolean data were met on the stack.
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
function PopBoolValues(Args: TsArgumentStack; NumArgs: Integer;
out AValues: TBoolArray; out AErrArg: TsArgument): Boolean;
var
arg: TsArgument;
err: TsErrorValue;
i: Integer;
counter, j: Integer;
b: Boolean;
begin
SetLength(AValues, NumArgs);
// Pop the data in reverse order they were pushed! Otherwise they will be
// applied to the function in the wrong order.
for i := NumArgs-1 downto 0 do begin
err := GetBoolFromArgument(Args.Pop, AValues[i]);
if err <> errOK then begin
Result := false;
AErrArg := CreateError(err);
SetLength(AValues, 0);
exit;
j := 0;
for counter := 1 to NumArgs do begin
arg := Args.Pop;
if not arg.IsMissing then begin
err := GetBoolFromArgument(arg, b);
if err = errOK then begin
AValues[j] := b;
inc(j);
end else begin
Result := false;
AErrArg := CreateError(err);
SetLength(AValues, 0);
exit;
end;
end;
end;
Result := true;
AErrArg := CreateError(errOK);
SetLength(AValues, j);
// Flip array - we want to have the arguments in the array in the same order
// they were pushed.
for j:=0 to Length(AValues) div 2 - 1 do begin
b := AValues[j];
AValues[j] := AValues[High(AValues)-j];
AValues[High(AValues)-j] := b;
end;
end;
{@@
@ -331,28 +334,46 @@ end;
@param AValues (output) Array containing the retrieved float values.
The array length is given by NumArgs. The data in the array
are in the same order in which they were pushed onto the stack.
Missing arguments are not included in the array, the case
of missing arguments must be handled separately if the are
important.
@param AErrArg (output) Argument containing an error code, e.g. errWrongType
if non-float data were met on the stack.
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
function PopFloatValues(Args: TsArgumentStack; NumArgs: Integer;
out AValues: TFloatArray; out AErrArg: TsArgument): Boolean;
var
arg: TsArgument;
err: TsErrorValue;
i: Integer;
counter, j: Integer;
val: double;
begin
SetLength(AValues, NumArgs);
// Pop the data in reverse order they were pushed! Otherwise they will be
// applied to the function in the wrong order.
for i := NumArgs-1 downto 0 do begin
err := GetNumberFromArgument(Args.Pop, AValues[i]);
if err <> errOK then begin
Result := false;
SetLength(AValues, 0);
AErrArg := CreateError(errWrongType);
exit;
j := 0;
for counter := 1 to NumArgs do begin
arg := Args.Pop;
if not arg.IsMissing then begin
err := GetNumberFromArgument(arg, val);
if err = errOK then begin
AValues[j] := val;
inc(j);
end else begin
Result := false;
SetLength(AValues, 0);
AErrArg := CreateError(errWrongType);
exit;
end;
end;
end;
Result := true;
SetLength(AValues, j);
// Flip array - we want to have the arguments in the array in the same order
// they were pushed.
for j:=0 to Length(AValues) div 2 - 1 do begin
val := AValues[j];
AValues[j] := AValues[High(AValues)-j];
AValues[High(AValues)-j] := val;
end;
AErrArg := CreateError(errOK);
end;
@ -364,29 +385,47 @@ end;
@param AValues (output) Array containing the retrieved strings. The array
length is given by NumArgs. The data in the array are in the
same order in which they were pushed onto the stack.
Missing arguments are not included in the array, the case
of missing arguments must be handled separately if the are
important.
@param AErrArg (output) Argument containing an error code , e.g. errWrongType
if non-string data were met on the stack.
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
function PopStringValues(Args: TsArgumentStack; NumArgs: Integer;
out AValues: TStrArray; out AErrArg: TsArgument): Boolean;
var
arg: TsArgument;
err: TsErrorValue;
i: Integer;
counter, j: Integer;
s: String;
begin
SetLength(AValues, NumArgs);
// Pop the data in reverse order they were pushed! Otherwise they will be
// applied to the function in the wrong order.
for i := NumArgs-1 downto 0 do begin
err := GetStringFromArgument(Args.Pop, AValues[i]);
if err <> errOK then begin
Result := false;
AErrArg := CreateError(errWrongType);
SetLength(AValues, 0);
exit;
j := 0;
for counter := 1 to NumArgs do begin
arg := Args.Pop;
if not arg.IsMissing then begin
err := GetStringFromArgument(arg, s);
if err = errOK then begin
AValues[j] := s;
inc(j);
end else begin
Result := false;
AErrArg := CreateError(errWrongType);
SetLength(AValues, 0);
exit;
end;
end;
end;
Result :=true;
Result := true;
AErrArg := CreateError(errOK);
SetLength(AValues, j);
// Flip array - we want to have the arguments in the array in the same order
// they were pushed.
for j:=0 to Length(AValues) div 2 - 1 do begin
s := AValues[j];
AValues[j] := AValues[High(AValues)-j];
AValues[High(AValues)-j] := s;
end;
end;
@ -826,6 +865,122 @@ begin
end;
{ Statistical functions }
function fpsAVEDEV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
// Average value of absolute deviations of data from their mean.
var
data: TFloatArray;
m: Double;
i: Integer;
begin
if PopFloatValues(Args, NumArgs, data, Result) then begin
m := Mean(data);
for i:=0 to High(data) do
data[i] := abs(data[i] - m);
m := Mean(data);
Result := CreateNumber(m)
end;
end;
function fpsAVERAGE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(Mean(data))
end;
function fpsCOUNT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ Count non-missing arguments }
var
n, i: Integer;
begin
n := 0;
for i:=1 to NumArgs do
if not Args.Pop.IsMissing then inc(n);
Result := CreateNumber(n);
end;
function fpsMAX(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(MaxValue(data))
end;
function fpsMIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(MinValue(data))
end;
function fpsPRODUCT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
i: Integer;
p: Double;
begin
if PopFloatValues(Args, NumArgs, data, Result) then begin
p := 1.0;
for i:=0 to High(data) do
p := p * data[i];
Result := CreateNumber(p);
end;
end;
function fpsSTDEV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(StdDev(data))
end;
function fpsSTDEVP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(PopnStdDev(data))
end;
function fpsSUM(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(Sum(data))
end;
function fpsSUMSQ(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(SumOfSquares(data))
end;
function fpsVAR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(Variance(data))
end;
function fpsVARP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TFloatArray;
begin
if PopFloatValues(Args, NumArgs, data, Result) then
Result := CreateNumber(PopnVariance(data))
end;
{ Logical functions }
function fpsAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
@ -901,4 +1056,31 @@ begin
Result := CreateBool(true);
end;
{ String functions }
function fpsLOWER(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
Result := CreateString(lowercase(data[0]));
end;
function fpsTRIM(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
Result := CreateString(trim(data[0]));
end;
function fpsUPPER(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
Result := CreateString(uppercase(data[0]));
end;
end.

View File

@ -1164,30 +1164,30 @@ const
(Symbol:'WEEKDAY'; MinParams:1; MaxParams:2; Func:nil), // fekWEEKDAY
(Symbol:'YEAR'; MinParams:1; MaxParams:1; Func:nil), // fekYEAR
{ statistical }
(Symbol:'AVEDEV'; MinParams:1; MaxParams:30; Func:nil), // fekAVEDEV
(Symbol:'AVERAGE'; MinParams:1; MaxParams:30; Func:nil), // fekAVERAGE
(Symbol:'AVEDEV'; MinParams:1; MaxParams:30; Func:fpsAVEDEV), // fekAVEDEV
(Symbol:'AVERAGE'; MinParams:1; MaxParams:30; Func:fpsAVERAGE), // fekAVERAGE
(Symbol:'BETADIST'; MinParams:3; MaxParams:5; Func:nil), // fekBETADIST
(Symbol:'BETAINV'; MinParams:3; MaxParams:5; Func:nil), // fekBETAINV
(Symbol:'BINOMDIST'; MinParams:4; MaxParams:4; Func:nil), // fekBINOMDIST
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2; Func:nil), // fekCHIDIST
(Symbol:'CHIINV'; MinParams:2; MaxParams:2; Func:nil), // fekCHIINV
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:nil), // fekCOUNT
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:fpsCOUNT), // fekCOUNT
(Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:nil), // fekCOUNTA
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1; Func:nil), // fekCOUNTBLANK
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2; Func:nil), // fekCOUNTIF
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:nil), // fekMAX
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:fpsMAX), // fekMAX
(Symbol:'MEDIAN'; MinParams:1; MaxParams:30; Func:nil), // fekMEDIAN
(Symbol:'MIN'; MinParams:1; MaxParams:30; Func:nil), // fekMIN
(Symbol:'MIN'; MinParams:1; MaxParams:30; Func:fpsMIN), // fekMIN
(Symbol:'PERMUT'; MinParams:2; MaxParams:2; Func:nil), // fekPERMUT
(Symbol:'POISSON'; MinParams:3; MaxParams:3; Func:nil), // fekPOISSON
(Symbol:'PRODUCT'; MinParams:0; MaxParams:30; Func:nil), // fekPRODUCT
(Symbol:'STDEV'; MinParams:1; MaxParams:30; Func:nil), // fekSTDEV
(Symbol:'STDEVP'; MinParams:1; MaxParams:30; Func:nil), // fekSTDEVP
(Symbol:'SUM'; MinParams:0; MaxParams:30; Func:nil), // fekSUM
(Symbol:'SUMIF'; MinParams:2; MaxParams:3; Func:nil), // fekSUMIF
(Symbol:'SUMSQ'; MinParams:0; MaxParams:30; Func:nil), // fekSUMSQ
(Symbol:'VAR'; MinParams:1; MaxParams:30; Func:nil), // fekVAR
(Symbol:'VARP'; MinParams:1; MaxParams:30; Func:nil), // fekVARP
(Symbol:'PRODUCT'; MinParams:0; MaxParams:30; Func:fpsPRODUCT), // fekPRODUCT
(Symbol:'STDEV'; MinParams:1; MaxParams:30; Func:fpsSTDEV), // fekSTDEV
(Symbol:'STDEVP'; MinParams:1; MaxParams:30; Func:fpsSTDEVP), // fekSTDEVP
(Symbol:'SUM'; MinParams:0; MaxParams:30; Func:fpsSUM), // fekSUM
(Symbol:'SUMIF'; MinParams:2; MaxParams:3; Func:nil), // fekSUMIF
(Symbol:'SUMSQ'; MinParams:0; MaxParams:30; Func:fpsSUMSQ), // fekSUMSQ
(Symbol:'VAR'; MinParams:1; MaxParams:30; Func:fpsVAR), // fekVAR
(Symbol:'VARP'; MinParams:1; MaxParams:30; Func:fpsVARP), // fekVARP
{ financial }
(Symbol:'FV'; MinParams:3; MaxParams:5; Func:nil), // fekFV
(Symbol:'NPER'; MinParams:3; MaxParams:5; Func:nil), // fekNPER
@ -1205,14 +1205,14 @@ const
(Symbol:'CHAR'; MinParams:1; MaxParams:1; Func:nil), // fekCHAR
(Symbol:'CODE'; MinParams:1; MaxParams:1; Func:nil), // fekCODE
(Symbol:'LEFT'; MinParams:1; MaxParams:2; Func:nil), // fekLEFT
(Symbol:'LOWER'; MinParams:1; MaxParams:1; Func:nil), // fekLOWER
(Symbol:'LOWER'; MinParams:1; MaxParams:1; Func:fpsLOWER), // fekLOWER
(Symbol:'MID'; MinParams:3; MaxParams:3; Func:nil), // fekMID
(Symbol:'PROPER'; MinParams:1; MaxParams:1; Func:nil), // fekPROPER
(Symbol:'REPLACE'; MinParams:4; MaxParams:4; Func:nil), // fekREPLACE
(Symbol:'RIGHT'; MinParams:1; MaxParams:2; Func:nil), // fekRIGHT
(Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4; Func:nil), // fekSUBSTITUTE
(Symbol:'TRIM'; MinParams:1; MaxParams:1; Func:nil), // fekTRIM
(Symbol:'UPPER'; MinParams:1; MaxParams:1; Func:nil), // fekUPPER
(Symbol:'TRIM'; MinParams:1; MaxParams:1; Func:fpsTRIM), // fekTRIM
(Symbol:'UPPER'; MinParams:1; MaxParams:1; Func:fpsUPPER), // fekUPPER
{ lookup/reference }
(Symbol:'COLUMN'; MinParams:0; MaxParams:1; Func:nil), // fekCOLUMN
(Symbol:'COLUMNS'; MinParams:1; MaxParams:1; Func:nil), // fekCOLUMNS

View File

@ -680,6 +680,193 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(tanh(0.1));
{------------------------------------------------------------------------------}
{ Statistical functions }
{------------------------------------------------------------------------------}
// AVEDEV
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=AVEDEV(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekAVEDEV, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(mean([0.0, 0.1, 0.2, 0.1, 0.2]));
// these values are the absolute deviations from mean (1.0)
// AVERAGE
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=AVERAGE(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekAVERAGE, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(mean([1.0, 1.1, 1.2, 0.9, 0.8]));
// COUNT (no missing values)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekCOUNT, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(5);
// COUNT (with missing values)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNT(1, , 1.2, , 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNMissingArg(
RPNNumber(1.2,
RPNMissingArg(
RPNNumber(0.8,
RPNFunc(fekCOUNT, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(3);
// MAX
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekMAX, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MaxValue([1.0, 1.1, 1.2, 0.9, 0.8]));
// MAX (with missing values)
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MAX(1, , , 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNMissingArg(
RPNMissingArg(
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekMAX, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MaxValue([1.0, {1.1, 1.2,} 0.9, 0.8]));
// MIN
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=MIN(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekMIN, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(MinValue([1.0, 1.1, 1.2, 0.9, 0.8]));
// PRODUCT
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=PRODUCT(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekPRODUCT, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(1.0*1.1*1.2*0.9*0.8);
// STDEV
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=STDEV(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekSTDEV, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(StdDev([1.0, 1.1, 1.2, 0.9, 0.8]));
// STDEVP
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=STDEVP(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekSTDEVP, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(PopnStdDev([1.0, 1.1, 1.2, 0.9, 0.8]));
// SUM
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=SUM(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekSUM, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(Sum([1.0, 1.1, 1.2, 0.9, 0.8]));
// SUMSQ
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=SUMSQ(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekSUMSQ, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(SumOfSquares([1.0, 1.1, 1.2, 0.9, 0.8]));
// VAR
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=VAR(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekVAR, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(Variance([1.0, 1.1, 1.2, 0.9, 0.8]));
// VARP
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=VARP(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekVARP, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumber(PopnVariance([1.0, 1.1, 1.2, 0.9, 0.8]));
{------------------------------------------------------------------------------}
{ Logical functions }
{------------------------------------------------------------------------------}
@ -854,3 +1041,34 @@
sollValues[Row] := CreateString('A');
{------------------------------------------------------------------------------}
{ String functions }
{------------------------------------------------------------------------------}
// Lower case
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=LOWER("Hallo word")');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNString('Hallo world',
RPNFunc(fekLOWER, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString(LowerCase('Hallo world'));
// Trim
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=TRIM(" Hallo word ")');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNString(' Hallo world ',
RPNFunc(fekTRIM, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString(Trim(' Hallo world '));
// Upper case
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=UPPER("Hallo word")');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNString('Hallo world',
RPNFunc(fekUPPER, nil))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString(UpperCase('Hallo world'));