简体   繁体   中英

Bitwise multiplication and division not working with large numbers

I'm trying to get this problem to work where I have to multiply 3/8 in bit and then round towards zero.

So far I have this

((((x<<1)+x)>>3)+((x>>31)&1));

The idea behind it is that the first part takes x and shifts it left 1 and adds x to get the multiplied by 3 effect and then shifts right 3 to get the divide by 8 part. Then I would add 1 if it is negative by testing to see if the sign bit is 1 (1&1 = 1) or 0 (0&1 = 0). My code won't work though, the tests are off.

Any ideas what I am doing wrong?

The left shifts that you use in effect shifts the individual bits as an unsigned integer so that you could wind up losing the sign bit. That is not what it sounds like you want. Try the multiplication to see what you should be getting against the bit shift to see what you are getting.

x *= 3.0/8.0;

Note the manual entry below showing that if the signed bit is affected the result is undefined

Left shift

The left-shift operator causes the bits in shift-expression to be shifted to the left by the number of positions specified by additive-expression. The bit positions that have been vacated by the shift operation are zero-filled. A left shift is a logical shift (the bits that are shifted off the end are discarded, including the sign bit). For more information about the kinds of bitwise shifts, see Bitwise shifts.

The following example shows left-shift operations using unsigned numbers. The example shows what is happening to the bits by representing the value as a bitset. For more information, see bitset Class.

If you left-shift a signed number so that the sign bit is affected, the result is undefined . The following example shows what happens in Visual C++ when a 1 bit is left-shifted into the sign bit position.

#include <iostream>
#include <bitset>
using namespace std;

int main() {
  short short1 = 16384;    
  bitset<16> bitset1{short2};
  cout << bitset1 << endl;  // 0100000000000000 

  short short3 = short1 << 1;
  bitset<16> bitset3{short3};  // 16384 left-shifted by 1 = -32768
  cout << bitset3 << endl;  // 100000000000000

  short short4 = short1 << 14;
  bitset<16> bitset4{short4};  // 4 left-shifted by 14 = 0
  cout << bitset4 << endl;  // 000000000000000  
}

You are overflowing your format by testing with the most negative number and then trying to multiply it to a larger (ie, even more negative) number.

There are various ways to fix this.

  1. Use something larger like int64.
  2. Use a second value to hold the overflow.
  3. Split the value in half and then compute it as a polynomial.

For the one test case, you could divide first and then multiply, and it would "work", but it would fail for all the cases where you then lose bits off the right side.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM