Rafał Majewski
Rafał Majewski

Reputation: 83

Printing bits in long long number (C++)

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.

Upvotes: 8

Views: 696

Answers (3)

Bo Persson
Bo Persson

Reputation: 92271

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).

Upvotes: 3

Kostas
Kostas

Reputation: 4176

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'

Upvotes: 3

Cpp plus 1
Cpp plus 1

Reputation: 1010

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

std::cout<<(bool)(number&(((long long)1)<<i));

Upvotes: 4

Related Questions