コードのテストに助けが必要なようです。ここでは、コメントで説明されているように、非常に単純なテストです。
{$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.
y(x) = 1
[0..1] の範囲で関数を統合しています。したがって、期待される出力は 1 ですが、実際の出力は 2 です。
それで、何が問題なのですか?デバッガーで解決できますが、コードを調べれば簡単に確認できます。最初のサンプルで三角形を合計しています。が真の場合IsNaN(LastValue)
、積分に寄与するべきではありません。その時点で、x 軸上の距離をカバーしていません。
コードを修正するために、これを試してみましょう。
....
if (IsNaN(LastValue)) then begin
hl := 0.0;//no contribution to sum
hr := 0.0;
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
....
これで問題は解決しました。
それでは、テストを少し拡張してテストしましょう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)]);
それで、それはよさそうです。
OK、複数の呼び出しはどうですか:
// 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)]);
一度に 1 つの値についてはどうでしょうか。
// 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)]);
空の配列を渡すとどうなりますか?
// 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)]);
アクセス違反です。バッファが空の場合、最初に関数をスキップするだけで、より適切に保護できます。
if (AVPS < 1) then exit;
if (Length(ABuffer) = 0) then exit;
OK、これで最後のテストに合格しました
うまくいけば、あなたは今アイデアを得るでしょう。noddyWriteln
ベースのテストを使用しましたが、スケーリングしません。単体テスト フレームワーク (DUnitX をお勧めします) を用意し、適切なテスト ケースを作成します。これにより、適切に設計されるようにコードを因数分解することも強制されます。コードをテスト可能にすることの予想外の利点の 1 つは、通常、インターフェイスの設計が改善されることです。
次の質問ですが、SSCCEにテスト コードを添付してください。;-)
コードに関するいくつかのコメント:
const
または によって動的配列を渡しますvar
。あなたの場合、入力バッファをconst
.
- 書き込み可能な型付き定数は使用しないでください。パラメータを使用するか、他のより適切な状態管理を使用してください。
繰り返しますが、前の質問で述べたように、コードを証明するテストを作成し、目で確認します。テストを書く上で重要なことは、考えられる最も単純なことから始めることです。答えが 100% 確実にわかるほど単純なこと。次に、それが機能するようになったら、テストをより複雑なケースに拡張します。