Thread: Bit shifts

  1. #1
    Registered User
    Join Date
    May 2005
    Posts
    48

    Bit shifts

    I'm converting some code from Fortran to C and I've run into a problem with the random number generator convertion. It seems that when doing a bit shift in C it produces a different result than the bitshift in the Fortran. Does anyone have any ideas on how this would happen? Since the generator depends on these shifts I can't convert the code correctly if the shift is not going to work the same way.
    Thanks

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well unless you post code, it's hard to say

    But shifting negative numbers right in C++ is implementation specific.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jun 2004
    Posts
    722
    bit shifting in C/C++ disregards the content of variables, only regards the size and the fact of not being floating point, because floating point operations are done by the co-processor

  4. #4
    Registered User
    Join Date
    May 2005
    Posts
    48
    Hmm, well I think I found the problem, but I don't know if it is solvable. I realized that the integers in the Fortran code are not actually 4 bytes long (as was initially told) but actually just have a precision to 9 decimal digits (-999999999 to 999999999). This would mean that any bit shift using normally declared variables in C are going to be different because of the precision. Anyt thoughts on how to get around this would be apreciated, also please note that the Fortran code cannot change.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well that fits nicely into 4 bytes - what's the problem?

    How about posting some example results, and perhaps we can figure out what is going on
    Say, in your fortran code, what does 1234 shifted 4 places left and 4 places right get you?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    May 2005
    Posts
    48
    Well, the problem doesn't present itself until you put in big numbers. Thats why I guessed that the problem was in the size of the integer. The 4 bit int does not go from -999999999 to 999999999, it has a smaller range in C++, as far as I know. Anyway, I'm using long in the C code to make sure that I'm getting 4 bit integers.
    The results are here:
    C++:
    777755849 << 5 results in 24888187168
    And the same number in Fortran shifted 5 left results in:
    -881616608

  7. #7
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Try using a signed int or long.
    Code:
       signed int num;
    
       num = (signed int) 777755849 << 5;
       cout << num << endl;

  8. #8
    Registered User
    Join Date
    May 2005
    Posts
    48
    That worked for the first number generated, but then:
    C++:
    ix = -9054424
    ix = 9054354
    The first number is the initial then the second is shifted 17 to the right
    and Fortran:
    ix = -9054424
    ix = -9066350
    under the same calculation

    Also, I forgot to say the exact calculation includes an exclusive or, the reason I left this out was because I determined the problem with the calculation was with the shift. The calculation is this:
    Code:
    ix = ix ^ (ix >> 17);

  9. #9
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Code:
    #include <iostream>
    
    void foo(int ix)
    {
       std::cout << "foo: ix = " << ix << std::endl;
       std::cout << "foo: ix >> 17 = " << (ix >> 17) << std::endl;
       ix = ix ^ (ix >> 17);
       std::cout << "foo: ix = " << ix << std::endl;
    }
    
    void bar(int ix)
    {
       std::cout << "bar: ix = " << ix << std::endl;
       std::cout << "bar: (unsigned)ix >> 17 = " << ((unsigned)ix >> 17) << std::endl;
       ix = ix ^ ((unsigned)ix >> 17);
       std::cout << "bar: ix = " << ix << std::endl;
    }
    
    int main()
    {
       foo(-9054424);
       bar(-9054424);
       return 0;
    }
    
    /* my output
    foo: ix = -9054424
    foo: ix >> 17 = -70
    foo: ix = 9054354
    bar: ix = -9054424
    bar: (unsigned)ix >> 17 = 32698
    bar: ix = -9066350
    */
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  10. #10
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Confirming what Dave posted, it looks like you need to cast to unsigned int before you do any shift operation:
    Code:
       num = num ^ static_cast<unsigned int>(num) >> 17;
    Which is the opposite of what I posted before.

  11. #11
    Registered User
    Join Date
    May 2005
    Posts
    48
    The Fortran bit shifts eventually loops to zero and so the Fortran after shifting to the left enough will get to zero and stop. The C++ shift however will keep looping (it will go to 1, and then keep going). So does anyone know how to make the C not go to one (for example, a different shift command)

  12. #12
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Perhaps you should post some code, because as long as you cast to unsigned it should go to 0. For example:
    Code:
    #include <iostream>
    #include <climits>
    using namespace std;
    
    int main()
    {
       int num = 0x1;
       cout << hex << num << dec << endl;
       for (int i=0; i<sizeof(int)*CHAR_BIT; ++i)
       {
          num = static_cast<unsigned int>(num) << 1;
          cout << hex << num << dec << endl;
       }
    }

  13. #13
    Hardware Engineer
    Join Date
    Sep 2001
    Posts
    1,398
    ...random number generator convertion.
    If you're simply trying to generate a random number, it's easy in C/C++. You can use the standard rand() function. And, here's the cprogramming.com tutorial.

    Playing around with bits is always fun, but it can be tricky in C/C++ because an integer can be 16, 32, or even 64 bits depending on the system.

  14. #14
    Registered User
    Join Date
    Aug 2003
    Posts
    470
    Hmm, well I think I found the problem, but I don't know if it is solvable. I realized that the integers in the Fortran code are not actually 4 bytes long (as was initially told) but actually just have a precision to 9 decimal digits (-999999999 to 999999999). This would mean that any bit shift using normally declared variables in C are going to be different because of the precision. Anyt thoughts on how to get around this would be apreciated, also please note that the Fortran code cannot change.
    You can get larger range in C++ by using 64 bits. But how are you determining this precison? I wouldn't trust the Fortran write routines. You should also look at an assembly listing or manual to find the exact shifting and types the Fortran compiler is using.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bit processing in C
    By eliomancini in forum C Programming
    Replies: 8
    Last Post: 06-07-2005, 10:54 AM
  2. Porting from 32 bit machine to 64 bit machine!
    By anoopks in forum C Programming
    Replies: 10
    Last Post: 02-25-2005, 08:02 PM
  3. Bit Manipulation Questions
    By CPPNewbie in forum C++ Programming
    Replies: 7
    Last Post: 08-12-2003, 02:17 PM
  4. Array of boolean
    By DMaxJ in forum C++ Programming
    Replies: 11
    Last Post: 10-25-2001, 11:45 PM
  5. bit conversions
    By wazilian in forum C Programming
    Replies: 4
    Last Post: 10-25-2001, 08:59 PM