Looks like you need some help with testing the code. Here, as discussed in comments, is a very simple test.
{$APPTYPE CONSOLE}
uses
SysUtils, Math;
type
TDoubleDynArray = array of Double;
var
SumSum: double;
LastValue: double;
procedure Clear;
begin
SumSum := 0.0;
LastValue := NaN;
end;
procedure IntegrateBuffer(
ABuffer: TDoubleDynArray;
var AOutBuffer: TDoubleDynArray;
AVPS: integer
);
var
i: integer;
dt, aa, hl, hr: double;
begin
// protect from divide by zero
if (AVPS < 1) then exit;
dt := 1 / AVPS;
for i := 0 to high(ABuffer) do begin
if (i = 0) then begin
if (IsNaN(LastValue)) then begin
hl := ABuffer[0];
hr := ABuffer[0];
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
end else begin
hl := ABuffer[i -1];
hr := ABuffer[i];
end;
aa := 0.5 * dt * (hl + hr);
SumSum := SumSum + aa;
AOutBuffer[i] := SumSum;
end;
// remember the last value for next time
LastValue := ABuffer[high(ABuffer)];
end;
var
Buffer: TDoubleDynArray;
OutBuffer: TDoubleDynArray;
begin
// test y = 1 for a single call, expected output = 1, actual output = 2
Clear;
Buffer := TDoubleDynArray.Create(1.0, 1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);
Readln;
end.
I'm integrating the function y(x) = 1
over the range [0..1]. So, the expected output is 1. But the actual output is 2.
So, what's wrong? You can work it out in the debugger, but it's easy enough to see by inspecting the code. You are summing a triangle on the very first sample. When IsNaN(LastValue)
is true then you should not make a contribution to the integral. At that point you've not covered any distance on the x axis.
So to fix the code, let's try this:
....
if (IsNaN(LastValue)) then begin
hl := 0.0;//no contribution to sum
hr := 0.0;
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
....
That fixes the problem.
Now let's extend the test a little and test y(x) = x
:
// test y = x, expected output = 12.5
Clear;
Buffer := TDoubleDynArray.Create(0.0, 1.0, 2.0, 3.0, 4.0, 5.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);
So, that looks good.
OK, what about multiple calls:
// test y = x for multiple calls, expected output = 18
Clear;
Buffer := TDoubleDynArray.Create(0.0, 1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(2.0, 3.0, 4.0, 5.0, 6.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);
And how about one value at a time?
// test y = x for multiple calls, one value at a time, expected 0.5
Clear;
Buffer := TDoubleDynArray.Create(0.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);
What about passing an empty array?
// test y = x for multiple calls, some empty arrays, expected 0.5
Clear;
Buffer := TDoubleDynArray.Create(0.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := nil;
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);
Uh, oh, access violation. Better protect that by simply skipping the function at the start if the buffer is empty:
if (AVPS < 1) then exit;
if (Length(ABuffer) = 0) then exit;
OK, now that last test passes
Hopefully you get the idea now. I've just used noddy Writeln
based testing but that does not scale. Get yourself a unit test framework (I recommend DUnitX) and build proper test cases. This will also force you to factor your code so that it is well designed. One of the often unexpected benefits of making code testable is that it usually results in the design of the interface being improved.
For your next question, I request that you supply an SSCCE with the test code! ;-)
Some comments on the code:
- Pass dynamic arrays by
const
or by var
. In your case you want to pass the input buffer by const
.
- Don't use writeable typed constants. Use either parameters, or some other more sane state management.
Again, as I said in the previous question, write tests to prove code, as well as checking it by eye. The key to writing tests is to start with the very simplest thing you can possibly think of. Something so simple that you know for 100% sure the answer. Then, once you get that to work, expand the testing to more complex cases.