1

VarConv のようなものですが、より高度なカスタム バリアント PhysUnit を作成しています。これは、実数または複素数を使用して、ユニットの加算と減算だけでなく、乗算と除算も可能にします。正常に動作しますが、非常に遅くなります。

問題は、このカスタム バリアントが他のバリアント (integer や double などの単純な型、または VarComplex などの別のカスタム) をラップしているため、DoAdd、DoSubtract を実行するときに、最初に両方のオペランドが同じファミリ (長さなど) を持っているかどうかを確認し、次に必要に応じてそれらの 1 つを変換する量を追加します。

Left:=Left + Right*multiplier;

そのようなもの、ここで Left と Right はバリアントです。

コンパイラは、この行を一連の呼び出しに変換します。

_varCopy(tmp,Left);
_varAdd(tmp,Right*multiplier);
_varClear(Left);
_varCopy(Left,tmp);
_varClear(tmp);

実際には、一時的なバリアントとこれらすべての回避策のためにメモリを割り当て/割り当て解除しなくても、_varAdd で十分です。

残念なことに、_varAdd(Left,Right) と書くことはできません。VCL にリンクされていません。

したがって、問題は、とにかくそれを呼び出して、さまざまなオプションや他のライブラリを追加してコンパイルしたときに変更される可能性のある直接メモリアドレスへの厄介な呼び出しなしで、できるだけ「クリーン」にすることは可能ですか?

4

2 に答える 2

1

コンパイラがアンダースコアを@識別子として使用できないように変換するため、アンダースコア付きの関数を呼び出すことはできません。

ただし、アセンブラ関数はそれらを呼び出すことができます。元の宣言を使用してに変更できるためTVarDataVariantバリアントを常にキャストする必要はありません。

procedure _VarAdd(var Left: Variant; const Right: Variant);
asm
  jmp System.Variants.@VarAdd
end;

procedure _VarSub(var Left: Variant; const Right: Variant);
asm
  jmp System.Variants.@VarSub
end;

begin
  _VarAdd(Left, Right);
end;

しかし、高速にしたい場合にバリアントを使用するのは正しい方法ではありません。i := i + 1;それらは非常に遅く、一時変数/CPUレジスタを必要とせずにコンパイルされる整数演算のようなコンパイラのオプティマイザからの助けがあまりありません。

一般的なケースに特別な処理を使用することで、バリアントを高速化できます。

if TVarData(Left).VType = TVarData(Right).VType then
begin
  case TVarData(Left).VType of
    varSingle:
      begin
        TVarData(Left).VSingle := TVarData(Left).VSingle + TVarData(Right).VSingle * M;
        Exit;
      end;
    varDouble:
      begin
        TVarData(Left).VDouble := TVarData(Left).VDouble + TVarData(Right).VDouble * M;
        Exit;
      end;
  end;
end;
 // use the slow function for all other cases
_VarAdd(Left, Right * M);
于 2015-09-29T09:00:44.750 に答える
0

次のようなきれいな構文を使用する場合:

Left := Left + Right*multiplier;

次に、コンパイラにコードを生成させる必要があります。また、バリアントを使用しているため、生成されたコードのパフォーマンスは非常に悪くなります。

関数を直接呼び出して操作を実行する場合は、バリアントを使用しても意味がありません。タイプ (おそらくレコード) を作成し、そのタイプにいくつかのメソッドを追加して、それらのメソッドを直接呼び出すことができます。

ただし、算術演算子をサポートする型を作成する必要があり、パフォーマンスを重視する場合は、 records で演算子のオーバーロードを使用する必要があります。

于 2015-09-29T08:51:32.350 に答える