Anonimous methods (aka Closures) are rare visitors in Delphi code. I have upgraded to Delphi 2009 a year before and never used the anonimous methods. But last week it finally happened.
I was writing the unit tests for fast fourier transform code. The idea of some tests was to compare the results of fast fourier trasform and discrete fourier transform of arbitrary function, and it appeared that the anonimous method is the best way to pass the function to the test.
type
TRealFunc = reference to function(N: Integer): Extended;
type
TTestFFT = class(TTestCase)
private
procedure TestRealFunc(Func: TRealFunc; Count: Integer);
published
procedure TestRealFFT00;
...
end;
All checks are done within TestRealFunc procedure. It receives a function to transform as an argument, makes fourier transform of the function using two different methods and compares the results:
procedure TTestFFT.TestRealFunc(Func: TRealFunc; Count: Integer);
var
FFTData: array of Extended;
DFTData: array of TksComplex;
M, N: Integer;
Arg: TksComplex;
begin
SetLength(FFTData, Count);
SetLength(DFTData, Count);
for M:= 0 to Count - 1 do begin
FFTData[M]:= Func(M);
// discrete Fourier transform;
DFTData[M]:= 0;
for N:= 0 to Count - 1 do begin
Arg.Re:= 0;
Arg.Im:= (2 * Pi * N * M) / Count;
DFTData[M]:= DFTData[M] + Func(N) * TksComplex.Exp(Arg);
end;
end;
// fast Fourier transform
RealFFT(@FFTData[0], Count, False);
CheckEquals(FFTData[0], DFTData[0].Re, 1E-15);
CheckEquals(FFTData[1], DFTData[Count shr 1 - 1].Re, 1E-15);
CheckEquals(0, DFTData[0].Im, 1E-15);
CheckEquals(0, DFTData[Count shr 1 - 1].Im, 1E-15);
for N:= 1 to Count shr 1 - 1 do begin
CheckEquals(FFTData[2 * N], DFTData[N].Re, 1E-15);
CheckEquals(FFTData[2 * N + 1], DFTData[N].Im, 1E-15);
CheckEquals(FFTData[2 * N], DFTData[Count - N].Re, 1E-15);
CheckEquals(FFTData[2 * N + 1], - DFTData[Count - N].Im, 1E-15);
end;
end;
The test procedures themselves just calls the TestRealFunc with different arguments. For example,
procedure TTestFFT.TestRealFFT00;
begin
TestRealFunc(
function(N: Integer): Extended
begin
Result:= Sin(pi / 4 * N) + 0.5 * Sin(pi / 2 * N + 3 * pi / 4);
end,
8
);
end;
Though the syntax looks cumbersome, the solution based on anonimous methods is very logical.