C - Saturating Signed Integer Multiplication with Bitwise Operators

时光总嘲笑我的痴心妄想 提交于 2020-01-13 20:25:45

问题


Alright, so the assignment I have to do is to multiply a signed integer by 2 and return the value. If the value overflows then saturate it by returning Tmin or Tmax instead. The challenge is using only these logical operators (! ~ & ^ | + << >>) with no (if statements, loops, etc.) and only allowed a maximum of 20 logical operators.

Now my thought process to tackle this problem was first to find the limits. So I divided Tmin/max by 2 to get the boundaries. Here's what I have:

Positive

This and higher works:

1100000...

This and lower doesn't:

1011111...

If it doesn't work I need to return this:

100000...

Negative

This and lower works:

0011111...

This and higher doesn't:

0100000...

If it doesn't work I need to return this:

011111...

Otherwise I have to return:

2 * x;

(the integers are 32-bit by the way)

I see that the first two bits are important in determining whether or not the problem should return 2*x or the limits. For example an XOR would do since if the first to bits are the same then 2*x should be returned otherwise the limits should be returned. Another if statement is then needed for the sign of the integer for it is negative Tmin needs to be returned, otherwise Tmax needs to be.

Now my question is, how do you do this without using if statements? xD Or a better question is the way I am planning this out going to work or even feasible under the constraints? Or even better question is whether there is an easier way to solve this, and if so how? Any help would be greatly appreciated!


回答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

So how does this work. The first two lines use the arithmetic right shift to fill the whole integer with a selected bit.

The last line is basically the "if statement". If a==b then the right hand side evaluates to 0 and none of the bits in x are flipped. Otherwise it must be the case that a==~b and the right hand side evaluates to x^b^0x80000000. After the statement is applied x will equal x^x^b^0x80000000 => b^0x80000000 which is exactly the saturation value.

Edit:

Here is it in the context of an actual program.

#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);
    }
}



回答2:


You have a very good starting point. One possible solution is to look at the first two bits.

abxx xxxx

Multiplication by 2 is equivalent to a left shift. So our result would be

bxxx xxx0

We see if b = 1 then we have to apply our special logic. The result in such a case would be

accc cccc

where c = ~a. Thus if we started with bitmasks

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

then when 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)

Clearly when b = 0 none of our special logic happens. It's straightforward to get these bitmasks in just a few operations. Disclaimer: I haven't tested this.



来源:https://stackoverflow.com/questions/29270939/c-saturating-signed-integer-multiplication-with-bitwise-operators

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!