0

私はコードをもっている:

    if (Ly0 > 32767) {
        buffer[index] = 32767;
    } else if (Ly0 < -32768) {
        buffer[index] = -32768;
    } else {
        buffer[index] = (short) Ly0;
   }
  • bufferショートタイプです。
  • Ly0フロートタイプです。

float の整数部分が short の最大値 short よりも short が short の最大値に等しい場合、および float の整数部分が short の min 値よりも小さい short が short の min 値に等しい場合は、float を short にキャストする必要があります。 float を short に変換し、float の整数値のみを取得します。

つまり、フロートからショートにキャストし、ショートの範囲外の場合はフロートを切り捨てる必要があります。

問題は、このアプローチが十分に速くなく、堅苦しいことです。

float を short に変換する最も高速でクリーンな方法です。

4

3 に答える 3

3

sse 組み込み関数を使用すると、最初に整数に変換してから、long int から short int への飽和変換を実行できます ( PACKSSDWを使用)。

「移植可能な」方法は、たとえばORCを使用することです。これは、mmx、sse、neon、および avs を使用する最適化されたインナーループのランタイム コンパイル用のライブラリです。互換性のあるシリアル実装を提供するだけでなく。

その前でも、コンパイラの出力を確認したい場合があります。例えば。などを使用するとgcc -ffast-math -O3 、コンパイラーはすでに xmm 命令を生成し、コンパイル時に反復回数がわかっている大きなループを並列化できることがよくあります。「運 == ブルート フォース」を使用すると、コンパイラが飽和パック パターンを認識できる形式に C コードを微調整できる可能性があります。多くの場合、中間計算の種類を細かく管理することに依存します。(比較は符号付きか符号なしか、int 型か short 型など)

于 2012-12-23T09:48:00.800 に答える
0

かなり優れたコンパイラがあり、実際にこれをループで実行している場合、コンパイラに「これを最適化する」という良いヒントを与えると仮定すると、コンパイラは何をしているのかを理解し、「賢い」を使用できるはずです。 SSE/SSE2 などの命令 - もちろん、コンパイルするプロセッサがそれをサポートしていると仮定します。

それ以外の場合は、コンパイラ固有の拡張機能またはインライン アセンブラを使用することを選択します。gcc コンパイラと MS コンパイラの両方に、この種のことを行うための組み込み関数があります。または、示唆されているように、これをうまく行う外部ライブラリが存在する可能性があります。繰り返しますが、この種の操作に対するプロセッサのサポートがあると仮定します。

最後の提案として、(一部のプロセッサでは) 次のようなことを行う方が高速である可能性があります。

int x = Ly0;
if (x > 32767) x = 32767;
else if (x < -32768) x = -32768;
buffer[index] = (short)x; 

その理由は、浮動小数点の比較は整数の比較よりもコストがかかる場合があり、コンパイラはこのコードをより適切に最適化する可能性があるためです。しかし、それは保証されていません - いつものように、ベンチマークと比較. コンパイラの出力を見て、それが理にかなっていると思うかどうかを確認するのは決して悪いことではありません!

編集: 上記のコードは、値が予想される範囲からそれほど離れていないことを前提としています。40億を超える値の場合、うまくいきません。その場合は、何があっても浮動小数点比較を使用する必要があります。

于 2012-12-23T10:03:27.193 に答える
-2

おそらく、この平和なコードを最適化する方法はありません。パフォーマンスの問題があるため、このコードはあるサイクル内で何度も実行されていると思います。サイクルの最適化を考える必要があります。たとえば、Ly0 値がランダム アクセス コンテナー内にある場合、最適化後に良い結果が得られる可能性があります。

for (int index = 0; index < (Ly0s.size() - 4); idx += 4) {
    do_conversion_for(index);
    do_conversion_for(index + 1);
    do_conversion_for(index + 2);
    do_conversion_for(index + 3);
}
switch (Ly0s.size() % 4){
    case 3:
        do_conversion_for(index + 3);
    case 2:
        do_conversion_for(index + 2);
    case 1:
        do_conversion_for(index + 1);
}

それ以外の

for (int index = 0; index < Ly0s.size(); ++idx) {
    do_conversion_for(index);
}
于 2012-12-23T09:45:30.407 に答える