优化:删除分支

时间:2015-03-10 14:49:53

标签: c math

我知道一点C.我试着编写一个程序,它不使用条件语句,但为给定的整数数组添加奇数和乘偶数。编写如果奇怪添加其他添加0 部分并不是很难。但是,我无法解决乘法部分的问题。解决方案似乎是乘以1,如果奇数,则为n

所以,我的问题是给定一个整数,如果它对给定的整数是奇数,你怎么能把它变换为1。没有条件允许。或者,如果可能的话,更好的主意。提前谢谢。

8 个答案:

答案 0 :(得分:4)

好的,要求提供答案。表达

res = (i % 2) + ((i+1) % 2) * number;
如果i为奇数,

将返回1,否则为number

答案 1 :(得分:3)

没有乘法,假设2s补码算术(如果没有,则将i转换为无符号):

/* implements odd(i) ? 1 : n */
(((i&1)-1)&(n-1)) + 1
  • 如果我是奇数,则i和1为1,否则为0,所以
  • (i& 1)-1如果i是奇数则为0,否则为-1。
  • 由于-1的2s补码表示将所有位设置为1:
  • ((i& 1)-1)&(n-1)如果i是奇数则为0,否则为(n-1),所以
  • (((i& 1)-1)&(n-1))+ 1如果i是奇数则为1,否则为n。

这是否比乘法更快取决于架构;在现代CPU上,它是值得怀疑的,但在嵌入式架构上却是如此。它当然不比编译器生成的条件移动快,并且它几乎不容易阅读。仍然...

答案 2 :(得分:2)

所以,让我无耻地撕掉@SeverinPappadeux的评论并稍微更改一下,以便我可以将其声称为我自己:

res = i % 2 + (1 - i % 2) * number;
      ^^^^^    ^^^^^^^^^
odd:    1         0
even:   0         1

答案 3 :(得分:2)

您可以轻松查看最后一位。这样,您就知道该数字是奇数或偶数。

last_bit = number & 0x01;
first_number = last_bit;

如果最后一位为零,则第一个数字为零。如果不是(奇数),那么它是1。

然后你取last_bit并反转最后一位

last_bit = (last_bit+1) & 0x01;
second_number = last_bit * n;

现在second_number是n或0。

result = (first_number + second_number);

答案 4 :(得分:1)

你去了:

int Get1IfOddValOtherwise(int val)
{
    return (1-(val&1))*(val-1)+1;
}

答案 5 :(得分:0)

res = (i % 2) ? 1: number;

条件执行,或者,分支预测是最好的镜头。

现在小枝条并不那么邪恶。

修改 它是分支预测 a ,而不是分支预测。

http://en.wikipedia.org/wiki/Branch_predication

答案 6 :(得分:0)

这是另一个无乘法版本(也假设有两个补码)。逻辑是&数字为11 ... 11(-1)为偶数(11 ... 1x,其中 x 不关心也会起作用......也许可以某种方式使用)和00 ... 01用于奇数。然后问题归结为将奇数和偶数转换为这些掩码。

n&(((n&1) << 1) - 1)

(n&1) << 1对偶数为0,对于奇数为2。减去一个会得到所需的面具。

(如上所述,你通常会更好地做n % 2 ? n : 1,而不是试图再次猜测优化器。编译器如果认为它可以生成无分支的条件移动。值得的。)

答案 7 :(得分:0)

在其他答案中,已经指出奇数和偶数的指标是i%2(i+1)%2

您可以使用它来解决一行中的完整问题:

result = (i%2)*(number+i)+((i+1)%2)*number*i

你必须关心i永远不会消极。如果仍然可以,那么您可以通过双模式操作来规范化情况:(2+i%2)%2(2+(i+1)%2)%2


当然,使用分支可以缩短,如

result = (i%2)?(i+number):(i*number)