【问题标题】:C - Saturating Signed Integer Multiplication with Bitwise OperatorsC - 用位运算符饱和有符号整数乘法
【发布时间】:2015-05-30 00:36:37
【问题描述】:

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

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

正面

这个和更高的作品:

1100000...

这个和更低的没有:

1011111...

如果它不起作用,我需要返回这个:

100000...

否定

这个和更低的作品:

0011111...

这个和更高版本没有:

0100000...

如果它不起作用,我需要返回这个:

011111...

否则我必须返回:

2 * x;

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

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

现在我的问题是,如何在不使用 if 语句的情况下做到这一点? xD 或者一个更好的问题是我计划这个工作的方式,甚至在限制条件下可行?或者更好的问题是是否有更简单的方法来解决这个问题,如果有,如何解决?任何帮助将不胜感激!

【问题讨论】:

  • CPU 能够做到这一点,方法是执行宽乘法并将饱和值cmoving 到结果中(如果高位非零)。但至于 C,我对此表示怀疑,而且它仍然比仅执行上述操作的库要慢。

标签: c bit-manipulation multiplication saturation-arithmetic


【解决方案1】:

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

abxx xxxx

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

bxxx xxx0

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

accc cccc

在哪里c = ~a。因此,如果我们从位掩码开始

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 没有发生我们的特殊逻辑时。只需几个操作即可轻松获得这些位掩码。免责声明:我没有测试过这个。

【讨论】:

    【解决方案2】:
    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 => 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);
        }
    }
    

    【讨论】:

    • 哈哈,我最初是在尝试自己的方式,并试图找到一种方法来执行 if 语句,但您似乎设法使它变得非常简单并且有很好的解释。这是我不得不做的更难的问题之一,我被困了一段时间,所以我想再次感谢你的解释和所有!
    猜你喜欢
    • 2013-10-13
    • 2013-07-08
    • 2013-06-02
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多