Reputation: 3621
If I run the following program:
#include <iostream>
int main()
{
using namespace std;
uint64_t f12 = 18446744073709551568;
uint64_t f3 = 2;
uint64_t f123 = f12 * f3;
cout << f12 << endl;
cout << f3 << endl;
cout << f123 << endl;
return 0;
}
I get as output:
18446744073709551568
2
18446744073709551520
I don't understand why 2 times f12 results in a value that is less (by exactly 48). If the value rolled over due to reaching the size of the uint64 value, wouldn't it be quite different (unless this is an extreme coincidence)?
Upvotes: 1
Views: 89
Reputation: 275200
The shifting is a red herring.
64 bit unsigned math in C++ is math modulo 2 to the power 64. If 2*a is 48 less than a, then a is 2 to the power 64 minus 48.
Upvotes: 0
Reputation: 35154
Multiplying an integral value by 2 can be seen as a left shift of the bits. When you convert your number 18446744073709551568
to binary, then this is...
1111111111111111111111111111111111111111111111111111111111010000
If you shift these bits one left, then the result is...
1111111111111111111111111111111111111111111111111111111110100000
In the least significant byte, i.e. at the right end, 11010000
(decimal 208
) is replaced by 10100000
(decimal 160
), which is exactly your 48
less. All the higher significant bytes remain the same. So the overall result is 48
less, too.
Upvotes: 1
Reputation: 118292
You can chalk it up to "extreme coincidence". 18446744073709551568 in binary is
FFFFFFFFFFFFFFD0
We all discovered when we learned binary math that multiplication by two is equivalent to a left shift, which becomes:
FFFFFFFFFFFFFFA0
Note that D0
is
11010000
in binary, with the high bit set, so shifting left the lower 8 bits becomes
10100000
or A0
(with the high bit getting carried left).
And now, by computing what's FFFFFFFFFFFFFFA0
in decimal you'll get the answer to your question (you are kind of getting a clue already, since A0
is less than D0
by 30
hexadecimal, which happens to be, purely by accident, 48).
Upvotes: 3