8

I want to print all bits of a long long number. When I am doing it in main() everything is fine, but in printBits() function (where code is same) there is an extra 1 on 32th bit.

The code:

#include <iostream>

void printBits(long long number)
{
    std::cout<<number<<" -> ";
    for (char i=63; i>=0; --i)
    {
        std::cout<<(bool)(number&(1<<i));
    }
    std::cout<<std::endl;
}

int main()
{
    long long number=1;

    std::cout<<number<<" -> ";
    for (char i=63; i>=0; --i)
    {
        std::cout<<(bool)(number&(1<<i));
    }
    std::cout<<std::endl;

    printBits(number);

    return 0;
}

Result is:

1 -> 0000000000000000000000000000000000000000000000000000000000000001
1 -> 0000000000000000000000000000000100000000000000000000000000000001

Process returned 0 (0x0)   execution time : 0.012 s
Press any key to continue.

3 Answers3

4

The literal 1 defaults to an integer. Cast it to long long to solve the problem.

std::cout<<(bool)(number&(((long long)1)<<i));
Cpp plus 1
  • 990
  • 8
  • 25
3

As Cpp plus 1's answer shows you need to modify the (default int) literal 1 to a long long literal 1LL or 1ll.

However, you might be better off using std::bitset instead of your function:

#include <bitset>
long long number = 1;  // int number = 1;  also works
std::bitset<64> bits(number);
std::cout << number << " -> " << bits << std::endl;

yields:

1 -> 0000000000000000000000000000000000000000000000000000000000000001

The reason you are getting this output is because for the specific hardware/compiler you are using:

a << x operation works in the following way: a << (x mod (8 * sizeof(a)). Therefore for 1 you get 1 << (x mod 32). This means that on the 32nd loop iteration:

std::cout << (bool)(number & (1 << 32));
// becomes
std::cout << (bool)(number & (1 << 0));
// printing '1'
Kostas
  • 4,061
  • 1
  • 14
  • 32
  • I don't believe your explanation is correct since the same code is producing 2 different results. If what you said was true both loops would give the same thing. – NathanOliver May 01 '18 at 20:43
  • @NathanOliver is correct. The truth is that the asker invoked undefined behavior. – jxh May 01 '18 at 20:59
  • 1
    @jxh Sure, but no where does this answer say it is undefined behavior and defining the behavior makes it sound like it will always work this way. – NathanOliver May 01 '18 at 20:59
3

The reason for the different results is that the compiler (here clang 6.0) can produce different code in the main function and in printBits.

In main it is known that number is always 1, and never changes. It is also "obvious" that this can only produce a single 1 in the output. So the optimizer rewrites the loop as:

for (char i=64; i > 0; --i)
{
    std::cout<< (i == 1 ? 1 : 0);
}

Look ma, no shifts!

The assembly looks like this

012B13CC  mov         bl,40h    ; i = 40h = 64  
012B13CE  xchg        ax,ax     ; nop to align the loop
main+30h: 
012B13D0  xor         eax,eax  
012B13D2  cmp         bl,1      ; i == 1?
012B13D5  mov         ecx,esi  
012B13D7  sete        al  
012B13DA  push        eax  
012B13DB  call        edi       ; edi -> operator<<
012B13DD  dec         bl  
012B13DF  jg          main+30h (012B13D0h)  

In printBits it cannot optimize this way, as the function could possibly be called from elsewhere. So there it performs the shift (with the erroneous result).

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • 1
    Interesting that it wasn't able to optimize in the constant after inlining the function. – jxh May 01 '18 at 22:29
  • 1
    GCC does it too: https://tio.run/##zZBBCsIwEEX3OcWgIMki0CK4MGkXXsAztGmsA2lSktSN9OrGkipCT@AshmE@vPnz1TjyXqmU9miVmToNEl2IXjdDTcjDYQejRxsvGAM1zvaQm52GVntGngSWCrE7n5WbopSrIOUOeA07keWb80DVvfGA1ekoAOuqEMA5siyvjA2Hts4ZRlfcgZZSImMrbt7ezKO2nRFkJmQxC0ODln7dbV1XpSB/ZjtLv5w/6X72XsfJWyiW71J6qZtp@pD49Q0 – jxh May 01 '18 at 22:30