3

このファンキーで小さな 2D N 体シミュレーションは、暇なときに C# で作成しました。シリアル実装では非常にうまく機能し、約 1000 体まで良好なフレームレートで実行され、その時点で遅延が始まりました。

CPU の別々のコアで実行される別々のブロックで位置と速度の更新を行うようにアルゴリズムを変更したところ、わずかなパフォーマンスの向上に気付きました。

実際の計算に多くの時間が費やされ、シーンの実際の描画にも少し時間が費やされることに注意してください。

Microsoft Accelerator V2 ライブラリを今ダウンロードし、それを使用するためにコード全体をゼロから書き直しました。以前と同じように動作しますが、大幅に遅くなります。以前はスムーズに実行するためにほぼ 1000 ポイントを獲得できましたが、現在、Accelerator では約 10 ポイントしか獲得できません。

これが私のコードです。Accelerator で何かをしたのはこれが初めてなので、何かを失敗した可能性が高いです。

Testそれが私の最初のテストだったので、クラスが呼び出されます。nコンストラクターは、物体の x 位置と y 位置、x 速度と y 速度、および質量の長さの配列を作成するだけです。decは単なる減衰係数であるため、丸め誤差が爆発するのではなく内破g1.0fます。

Tick()すべての更新を実行する関数です。最初に任意の点 i に関するすべての点を考慮し、半径を見つけ、他の点の方向に単位ベクトルを作成し、その単位ベクトルを減速度と重力定数でスケーリングし、合計して x 速度と y 速度を更新します。その点のために。

次に、すべての速度とすべての位置を更新し、float[]s に戻します。

私が言ったように、コードは技術的に機能します。結果は、大幅な速度低下を除いて、私のシリアル実装と同じです。

私が間違っているかもしれないアイデアはありますか?

85 行目と 86 行目かもしれません。点 i の x 速度と y 速度の更新を合計し、それを float 配列に格納していTarget.ToArray1D()[0]ます。つまり、合計値を取得するために呼び出す必要があります。

これを行う理由は、最初にすべてのポイントを更新し、次にポイントを更新してから、速度に基づいて位置の変更を適用するためです。

つまり、時間t + 1でポイント0を時間tの残りのポイントで更新し、次にポイント1を時間tで再び残りのポイントで更新するが、ポイント 0 を新しいtで更新する状況は望ましくありません。 + 1 . それが理にかなっていれば。

public void Tick()
{
    FPA fxPos = new FPA(xPos);
    FPA fyPos = new FPA(yPos);
    FPA fxVel = new FPA(xVel);
    FPA fyVel = new FPA(yVel);
    FPA fMass = new FPA(mass);

    float[] xUpd = new float[n]; // x-update for velocity
    float[] yUpd = new float[n]; // y-update for velocity

    for (int i = 0; i < n; i++)
    {
        // x- and y-pos about point i:
        FPA ixPos = PA.Subtract(fxPos, xPos[i]);
        FPA iyPos = PA.Subtract(fyPos, yPos[i]);

        // radius from point i:
        FPA iRad = PA.Sqrt(PA.Add(PA.Multiply(ixPos, ixPos), PA.Multiply(iyPos, iyPos)));

        // x- and y-pos are now unit vectors:
        ixPos = PA.Divide(ixPos, iRad);
        iyPos = PA.Divide(iyPos, iRad);

        // vectors are now scaled by mass:
        ixPos = PA.Multiply(fMass, ixPos);
        iyPos = PA.Multiply(fMass, iyPos);

        // vectors are now scaled by G and deceleration:
        ixPos = PA.Multiply(dec * g, ixPos);
        iyPos = PA.Multiply(dec * g, iyPos);

        // sum to get ith update value:
        xUpd[i] = target.ToArray1D(PA.Sum(ixPos))[0];
        yUpd[i] = target.ToArray1D(PA.Sum(iyPos))[0];
    }

    FPA fxUpd = new FPA(xUpd);
    FPA fyUpd = new FPA(yUpd);

    // update velocities:
    fxVel = PA.Add(fxUpd, fxVel);
    fyVel = PA.Add(fyUpd, fyVel);

    // update positions:
    fxPos = PA.Add(fxVel, fxPos);
    fyPos = PA.Add(fyVel, fyPos);

    xPos = target.ToArray1D(fxPos);
    yPos = target.ToArray1D(fyPos);
    xVel = target.ToArray1D(fxVel);
    yVel = target.ToArray1D(fyVel);
}
4

1 に答える 1

1

実際に並列コンピューティングを使用するには、ロジックを再検討する必要があります。あなたはまだ一度に1つのポイントで作業しています。ライブラリの利点を利用するには、要素の配列全体に対して 1 つのアクションを検討する必要があります。

于 2012-09-19T07:25:17.833 に答える