C - 使用逐位运算符对带符号整数乘法进行饱和

时间:2015-03-26 04:07:35

标签: c bit-manipulation multiplication

好吧,所以我要做的是将有符号整数乘以2并返回该值。如果值溢出,则通过返回Tmin或Tmax来使其饱和。挑战是仅使用这些逻辑运算符(!〜& ^ | +<<>>>)而没有(if语句,循环等),并且最多只允许20个逻辑运算符。

现在我解决这个问题的思维过程首先要找到限制。所以我将Tmin / max除以2得到边界。这就是我所拥有的:

这个和更高的作品:

1100000...

这个和更低的不是:

1011111...

如果它不起作用,我需要退回:

100000...

否定

这个和更低的作品:

0011111...

这个和更高的不是:

0100000...

如果它不起作用,我需要退回:

011111...

否则我必须回复:

2 * x;

(顺便说一下整数是32位)

我看到前两位对于确定问题是否应该返回2 * x或限制很重要。例如,XOR会这样做,因为如果第一个到第一个位相同,则应返回2 * x,否则应返回限制。然后需要另一个if语句来表示整数的符号,因为它需要返回负Tmin,否则需要Tmax。

现在我的问题是,如何在不使用if语句的情况下执行此操作? xD或者更好的问题是我计划在约束下工作甚至可行的方式?或者更好的问题是,是否有更简单的方法来解决这个问题,如果是这样的话,怎么办?任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

你有一个非常好的起点。一种可能的解决方案是查看前两位。

abxx xxxx

乘以2相当于左移。所以我们的结果将是

bxxx xxx0

我们看是否b = 1然后我们必须应用我们的特殊逻辑。在这种情况下的结果将是

accc cccc

其中c = ~a。因此,如果我们开始使用bitmasks

m1 = 0bbb bbbb
m2 = b000 0000
m3 = aaaa aaaa & bbbb bbbb

然后是b = 1

x << 1;  // gives 1xxx xxxx
x |= m1; // gives 1111 1111
x ^= m2; // gives 0111 1111
x ^= m3; // gives accc cccc (flips bits for initially negative values)

显然,当b = 0没有我们的特殊逻辑发生时。只需几个操作即可直接获得这些位掩码。免责声明:我没有测试过这个。

答案 1 :(得分:1)

a = (x>>31); // fills the integer with the sign bit 
b = (x<<1) >> 31; // fills the integer with the MSB 
x <<= 1; // multiplies by 2
x ^= (a^b)&(x^b^0x80000000); // saturate

这是怎么回事。前两行使用算术右移用选定的位填充整数。

最后一行基本上是“if语句”。如果a==b,则右侧评估为0,并且x中的所有位都不会被翻转。否则,必须是 a==~b并且右侧评估为x^b^0x80000000的情况。 声明应用后x将等于x^x^b^0x80000000 =&gt; b^0x80000000这正是饱和度值。

编辑:

这是在实际程序的上下文中。

#include<stdio.h>
main(){
    int i = 0xFFFF;
    while(i<<=1){
        int a = i >> 31;
        int b = (i << 1) >> 31;
        int x = i << 1;
        x ^= (a^b) & (x ^ b ^ 0x80000000);
        printf("%d, %d\n", i, x);
    }
}