C语言 C中整数的快速符号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14579920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:11:47  来源:igfitidea点击:

Fast sign of integer in C

c

提问by Alex

There is a sign function in C:

C中有一个符号函数:

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

Unfortunately, comparison cost is very high, so I need to modify function in order reduce the number of comparisons.

不幸的是,比较成本非常高,所以我需要修改函数以减少比较次数。

I tried the following:

我尝试了以下方法:

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

    if (x > 0) return 1;

    return result;
}

In this case I get only one comparison.

在这种情况下,我只得到一个比较。

Is there any way to avoid comparisons at all?

有没有办法完全避免比较?

EDITpossible duplicatedoes not give an answer for a question as all answers are C++, uses comparison (that I supposed to avoid) or does not return -1, +1, 0.

编辑可能的重复不会给出问题的答案,因为所有答案都是 C++,使用比较(我应该避免)或不返回-1, +1, 0

回答by NPE

First of all, integer comparison is very cheap. It's branchingthat can be expensive (due to the risk of branch mispredictions).

首先,整数比较非常便宜。它的分支,可以是昂贵的(由于分支预测失误的风险)。

I have benchmarked your function on a Sandy Bridge box using gcc 4.7.2, and it takes about 1.2ns per call.

我已经使用 gcc 4.7.2 在 Sandy Bridge 机器上对您的函数进行了基准测试,每次调用大约需要 1.2ns。

The following is about 25% faster, at about 0.9ns per call:

以下大约快 25%,每次调用大约 0.9ns:

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

The machine code for the above is completely branchless:

上面的机器代码是完全无分支的:

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

Two things are worth pointing out:

有两点值得指出:

  1. The base level of performance is very high.
  2. Eliminating branching does improve performance here, but not dramatically.
  1. 性能的基础水平非常高。
  2. 消除分支确实可以提高这里的性能,但不会显着提高。

回答by Chris Dodd

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);
}

The first part (x>>32) gives you -1 for negative numbers and 0 for 0 or positive numbers. The second part gives you 1 if x > 0 or equal to INT_MIN, and 0 otherwise. Or gives you the right final answer.

第一部分 ( x>>32) 为负数提供 -1,0 或正数为 0。如果 x > 0 或等于 INT_MIN,则第二部分为 1,否则为 0。或者给你正确的最终答案。

There's also the canonical return (x > 0) - (x < 0);, but unfortunately most compilers will use branches to generate code for that, even though there are no visible branches. You can try to manually turn it into branchless code as:

还有 canonical return (x > 0) - (x < 0);,但不幸的是,大多数编译器会使用分支来为此生成代码,即使没有可见的分支。您可以尝试手动将其转换为无分支代码:

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

which is arguably better than the above as it doesn't depend on implementation defined behavior, but has a subtle bug in that it will return 0 for INT_MIN.

这可以说比上面的更好,因为它不依赖于实现定义的行为,但有一个微妙的错误,它会为 INT_MIN 返回 0。

回答by Bruce

int sign(int x) {    
    return (x>>31)|(!!x);
}  

回答by anatolyg

If s(x)is a function that returns the sign-bit of x(you implemented it by ((unsigned int)x)>>31), you can combine s(x)and s(-x)in some way. Here is a "truth table":

Ifs(x)是一个返回符号位的函数x(您通过 实现了它((unsigned int)x)>>31),您可以以某种方式组合s(x)s(-x)。这是一个“真值表”:

x > 0: s(x) = 0; s(-x) = 1; your function must return 1

x < 0: s(x) = 1; s(-x) = 0; your function must return -1

x = 0: s(x) = 0; s(-x) = 0; your function must return 0

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

So you can combine them in the following way:

因此,您可以通过以下方式组合它们:

s(-x) - s(x)

回答by Aniket Inge

int i = -10;
if((i & 1 << 31) == 0x80000000)sign = 0;else sign = 1;
//sign 1 = -ve, sign 0 = -ve