是否可以在不使用任何乘法和条件/分支的情况下用-1/1优化整数的乘法?
只能用按位运算和整数加法完成吗?
编辑:最终目标是优化两个整数向量的标量积,其中一个向量仅具有-1/1值。
答案 0 :(得分:4)
例如,以下函数返回a*b
,其中b
是+1
或-1
:
int mul(int a, int b)
{
int c[3] = { -a, 0, +a };
return c[1+b];
}
或者a
和b
都限于+-1
:
int mul(int a, int b)
{
int c[5] = { +1, 0, -1, 0, +1 };
return c[a+b+2];
}
还有另一个没有内存访问的变体(比上面的变体快):
int mul(int a, int b)
{
return 1 - (signed)( (unsigned)(a+1) ^ (unsigned)(b+1) );
}
此答案适用于任何带符号的整数表示形式(符号幅度,1的补码,2的补码),并且不会引起任何未定义的行为。
但是,我不能保证它会比普通乘法快。
答案 1 :(得分:4)
大多数现代处理器的ALU都有一个快速乘法器(这意味着将两个数字相乘与将它们相乘,给定或占用一个CPU时钟大约需要相同的时间),因此除了for (i=0;i<VectorLength;++i) { p += (x[i] * y[i]) ; }
之外什么都不做可能会有所帮助。但是,请尝试使用简单的if
,看看是否可以从CPU的分支预测中获得任何好处:
for (i=0;i<VectorLength;++i) { p += (y[i]<0) ? -x[i] : x[i] ; }
在任何情况下,如果CPU具有快速乘法功能,则执行涉及多个ALU操作的任何技巧(例如,在此给出的某些示例中,求反后加法)将比只是一个乘法。
答案 2 :(得分:1)
int Multiplication(int x, int PlusOrMinusOne)
{
PlusOrMinusOne >>= 1; //becomes 0 or -1
//optionally build 2's complement (invert all bits plus 1)
return (x ^ PlusOrMinusOne) + (PlusOrMinusOne & 1);
}
这里是Bit Twiddling Hacks这样的好资源。
答案 3 :(得分:0)
严格来说,不,因为C允许三种不同的整数表示形式:
有一个proposal to strictly make it two's complement,但是直到成为标准之前,您都不知道自己的负数是什么样子,因此您无法真正对它们进行过多的修改。
严格地说,大多数实现使用二进制补码,因此使用其他答案中显示的hack是相当安全的。
答案 4 :(得分:0)
假设2对整数的补码:
int i1 = ...; // +1 or -1
int i2 = ...; // +1 or -1
unsigned u1 = i1 + 1; // 0 or 2
unsigned u2 = i2 + 1; // 0 or 2
unsigned u = u1 + u2; // 0 or 2 or 4: 0 and 4 need to become 1, 2 needs to become -1
u = (u & ~4); // 0 is 1 and 2 is -1
int i = u - 1; // -1 is 1 and 1 is -1
i = ~i + 1; // -1 is -1 and 1 is 1 :-)
与单线一样:
int i = ~(((i1 + i2 + 2) & ~4) - 1) + 1;
以下情况适用于i1
或i2
的{{1}}和+1
:
-1