12

Cにはsign関数があります:

int sign(int x)
{
    if(x > 0) return 1;
    if(x < 0) return -1;
    return 0;
}

残念ながら、比較コストが非常に高いため、比較の数を減らすために関数を変更する必要があります。

私は次のことを試しました:

int sign(int x)
{
    int result;
    result = (-1)*(((unsigned int)x)>>31);

    if (x > 0) return 1;

    return result;
}

この場合、比較結果は 1 つだけです。

比較をまったく回避する方法はありますか?

すべての回答が C++ である、比較を使用する (回避するはずだった)、または, , を返さないため、重複の可能性があるEDITは質問に対する回答を提供しません。-1+10

4

5 に答える 5

44

まず、整数比較は非常に安価です。費用がかかる可能性があるのは分岐です (分岐の予測ミスのリスクがあるため)。

gcc 4.7.2 を使用して Sandy Bridge ボックスで関数のベンチマークを行いました。呼び出しごとに約 1.2ns かかります。

以下は、呼び出しごとに約 0.9ns で、約 25% 高速です。

int sign(int x) {
    return (x > 0) - (x < 0);
}

上記のマシン コードは完全にブランチレスです。

_sign:
    xorl    %eax, %eax
    testl   %edi, %edi
    setg    %al
    shrl    $31, %edi
    subl    %edi, %eax
    ret

指摘する価値があるのは次の 2 点です。

  1. パフォーマンスの基本レベルは非常に高いです。
  2. ここで分岐をなくすとパフォーマンスは向上しますが、劇的ではありません。
于 2013-01-30T20:21:10.783 に答える
6
int sign(int x)
{
    // assumes 32-bit int and 2s complement signed shifts work (implementation defined by C spec)
    return (x>>31) | ((unsigned)-x >> 31);
}

最初の部分(x>>32)は、負の数の場合は-1、0または正の数の場合は0になります。2番目の部分では、x> 0またはINT_MINに等しい場合は1、それ以外の場合は0になります。またはあなたに正しい最終的な答えを与えます。

正規のものもありますreturn (x > 0) - (x < 0);が、残念ながら、ほとんどのコンパイラは、目に見えるブランチがない場合でも、ブランチを使用してそのコードを生成します。次のように、手動でブランチレスコードに変換してみることができます。

int sign(int x)
{
    // assumes 32-bit int/unsigned
    return ((unsigned)-x >> 31) - ((unsigned)x >> 31);
}

これは、実装で定義された動作に依存しないため、上記よりも間違いなく優れていますが、INT_MINに対して0を返すという微妙なバグがあります。

于 2013-01-30T19:48:29.660 に答える
2
int sign(int x) {    
    return (x>>31)|(!!x);
}  
于 2013-08-07T11:50:01.397 に答える
0

が(によって実装した)s(x)の符号ビットを返す関数である場合は、何らかの方法で組み合わせることができます。これが「真理値表」です。x((unsigned int)x)>>31s(x)s(-x)

x> 0:s(x)= 0; s(-x)= 1; 関数は1を返す必要があります

x <0:s(x)= 1; s(-x)= 0; 関数は-1を返す必要があります

x = 0:s(x)= 0; s(-x)= 0; 関数は0を返す必要があります

したがって、次の方法でそれらを組み合わせることができます。

s(-x) - s(x)
于 2013-01-30T19:47:21.847 に答える
-1
int i = -10;
if((i & 1 << 31) == 0x80000000)sign = 0;else sign = 1;
//sign 1 = -ve, sign 0 = -ve 
于 2013-01-30T19:44:07.403 に答える