0

少し異なるタイピングを使用して、高レベルのアプリケーションと低レベルのサブシステムの間にラッパー層を実装する必要があります。

アプリケーションは、単一ベクトルの配列を生成します。

unit unApplication
type

TVector = record
  x, y, z : single;
end;

TvectorArray = array of Tvector;

procedure someFunc(): tvectorArray;
[...]

一方、サブシステムは double ベクトルの配列を想定しています。また、tvector から Tvectord への型キャストも実装しました。

unit unSubSystem
type

TVectorD = record
  x, y, z : double;
  class operator Implicit(value : t3dVector):t3dvectorD;inline;
end;

TvectorDArray = array of TvectorD;

procedure otherFunc(points: tvectorDArray);

implementation 
    class operator T3dVecTorD.Implicit(value : t3dVector):t3dvectorD;
begin
  result.x := value.x;
  result.y := value.y;
  result.z := value.z;
end;

私が現在やっていることは次のようなものです:

uses unApplication, unsubsystem,...
procedure ConvertValues
var
  singleVecArr : TvectorArray;
  doubleveArr :  TvectorDArray; 
begin
  singleVecArr := somefunc;
  setlength(doubleVecArray, lenght(singlevecArr));
  for i := 0 to length(singlevecArr) -1 do
    doubleVecArray[i] := singleVecArr[i];
end;

これらの種類の変換を実行するより効率的な方法はありますか?

4

3 に答える 3

1

まず第一に、私はあなたが最初のタイミングなしでどんな最適化も試みるべきではないと言うでしょう。この場合、私は代替アルゴリズムのタイミングを意味するのではなく、問題のコードのタイミングを調整し、そこで費やされる合計時間の割合を評価することを意味します。

私の本能によれば、表示するコードは全体の時間のごく一部で実行されるため、最適化しても認識できるメリットはありません。この配列の各要素で何か意味のあることをするなら、それは真実でなければならないと思います。なぜなら、シングルからダブルへの変換のコストは浮動小数点演算と比較して小さいからです。

最後に、このコードがボトルネックである場合は、変換しないことを検討する必要があります。私の仮定は、8087FPUにマップする標準のDelphi浮動小数点演算を使用していることです。このような浮動小数点演算はすべて、8087浮動小数点スタック内で行われます。値は、入力時に64以上、通常は80ビットの精度に変換されます。ダブルをロードするよりもシングルをロードする方が遅いとは思いません。実際、メモリの読み取りパフォーマンスのために、さらに高速になる可能性があります。

于 2011-02-01T08:24:10.147 に答える
1

変換が実際にボトルネックであると仮定すると、変換を高速化する 1 つの方法は、FPU の代わりに SSE# を使用することです。ただし、このコードが実行されるコンピューターに必要な命令セットが存在すると想定できる場合に限ります。

たとえば、次の例では、1 つの単一のベクターを 1 つの double のベクターに変換します。

procedure SingleToDoubleVector (var S: TVector; var D: TVectorD);
// @S in EAX
// @D in EDX
asm
  movups    xmm0, [eax]     ;// Load S in xmm0
  movhlps   xmm1,  xmm0     ;// Copy High 2 singles of xmm0 into xmm1
  cvtps2pd  xmm2,  xmm0     ;// Convert Low two singles of xmm0 into doubles in xmm2
  cvtss2sd  xmm3,  xmm1     ;// Convert Lowes single in xmm1 into double in xmm1
  movupd   [edx],  xmm2     ;// Move two doubles in xmm2 into D (.X and .Y)
  movsd    [edx+16],xmm3    ;// Move one double from xmm3 into D.Z
end;

このコードが最も効率的な方法であると言っているわけではありません。一般的にアセンブリ コードを使用する場合、特にこのコードを使用する場合には多くの注意事項があります。このコードは、レコード内のフィールドの位置合わせについて想定していることに注意してください。(レコード全体のアラインメントに関する仮定は行いません。)

また、最良の結果を得るには、メモリ内の配列/レコード要素の配置を制御し、変換ループ全体をアセンブリに記述して、オーバーヘッドを削減します。これがあなたが望む/できるかどうかは別の問題です。

于 2011-02-01T10:23:02.577 に答える
0

シングルではなくダブルを生成するようにソースを変更できない場合は、プロセスをスレッド化してみることができます。TArray を 2 つまたは 4 つの等しいサイズのチャンク (プロセッサの数に応じて) に分割し、各スレッドで変換を実行してみてください。これを行うと、ほぼ2倍または4倍の速度が実現します。

また、「長さ」呼び出しはループごとに計算されますか? 計算を避けるために、それを変数に入れてください。

于 2011-02-01T05:49:49.203 に答える