使用+/- 1优化整数乘法

时间:2018-07-01 09:14:42

标签: c bitwise-operators

是否可以在不使用任何乘法和条件/分支的情况下用-1/1优化整数的乘法?

只能用按位运算和整数加法完成吗?

编辑:最终目标是优化两个整数向量的标量积,其中一个向量仅具有-1/1值。

5 个答案:

答案 0 :(得分:4)

例如,以下函数返回a*b,其中b+1-1

int mul(int a, int b)
{
    int c[3] = { -a, 0, +a };

    return c[1+b];
}

或者ab都限于+-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;

以下情况适用于i1i2的{​​{1}}和+1

-1