不使用abs函数或if语句获取绝对值

sha*_*nwu 53 c bit-manipulation

我在想如何在不使用if语句的情况下获取整数的绝对值abs().起初我使用左移位(<<),试图将负号移出范围,然后将位移回原位,但不幸的是它对我不起作用.请让我知道它为什么不起作用以及其他替代方法.

Has*_*kun 43

来自Bit Twiddling Hacks:

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;
Run Code Online (Sandbox Code Playgroud)

  • v >> sizeof(int)*CHAR_BIT - 1你能解释一下这是做什么的吗? (3认同)
  • @codeymodey:我没有写原文,但这取决于2的补码表示.如果符号位置位,它使掩码等于全1,因为它正在向右移位,这通常是算术移位,因此发生符号扩展.这相当于根据符号位将掩码设置为-1或0. (3认同)
  • 是不是正确转移签名的内部实现定义?基本上我们设置mask = 0x0表示正数,mask = 0xffffffff表示负数.不是" - ((无符号)数字>> 31)"是正确的还是更慢? (3认同)

per*_*eal 24

int abs(int v) 
{
  return v * ( (v<0) * (-1) + (v>0));
  // simpler: v * ((v>0) - (v<0))   thanks Jens
}
Run Code Online (Sandbox Code Playgroud)

此代码将vwith -1或的值乘以1得到abs(v).因此,括号内将是-1或之一1.

如果v为正,则表达式(v>0)为true,并且值为false 1(v<0)false为false(值为0表示false).因此,什么时候v是积极的((v>0) - (v<0)) = (1-0) = 1.整个表达是:v * (1) == v.

如果v是否定的,则表达式(v>0)为假,并且将具有值0(v<0)为真(值1).因此,对于否定v,((v>0) - (v<0)) = (0-1) = -1.整个表达是:v * (-1) == -v.

v == 0,既(v<0)(v>0)将评估为0,离开:v * 0 == 0.

  • 只做`v*((v> 0) - (v <0))`是等同的,更容易阅读,不是吗? (8认同)

Seb*_*ach 21

无网点*:

int abs (int n) {
    const int ret[2] = { n, -n };
    return ret [n<0];
}
Run Code Online (Sandbox Code Playgroud)

注4.7积分转换/ 4: [...] If the source type is bool, the value false is converted to zero and the value true is converted to one.


*:在您的代码中没有条件分支的意义上.在引擎盖下,三元运营商也将生产一个分支机构.但是,这也是一个有效的答案,因为三元不是if语句.这并不意味着您的编译器无法为逻辑分支的代码发出branchfree汇编代码.

  • C中的"无分支"可能不会被编译.有趣的是,"branchfree"实际上是目标代码的属性,而不是源代码的属性. (9认同)
  • 不,而且我的"可能"的风格是[优雅的laconian"If."](http://en.wikipedia.org/wiki/Laconic_phrase#Spartan).我认为这个问题没有太多价值,我的答案更多是一个有意识的大量示威:P (2认同)

小智 8

假设32位有符号整数(Java),您可以编写:

public static int abs(int x)
{
    return (x + (x >> 31)) ^ (x >> 31);
}
Run Code Online (Sandbox Code Playgroud)

没有乘法,没有分支.

顺便说一句,return (x ^ (x >> 31)) - (x >> 31);也会有效,但它已获得专利.对!

注意:此代码可能比条件语句(8位Verison)长10倍以上.这可能对硬件编程系统C等有用

  • 你怎么能为这样的东西申请专利呢? (2认同)
  • 问题是针对 `c`,而不是 `java`。-1. (2认同)
  • 该代码对于 c 和 java 都同样有效。将 int 替换为 int32_t (2认同)

小智 6

我在C中尝试此代码,并且可以正常工作。

int abs(int n){
   return n*((2*n+1)%2); 
}
Run Code Online (Sandbox Code Playgroud)

希望这个答案会有所帮助。

  • 导致大 n 溢出。 (4认同)