Bit shifts in c++ - c++

I don't understand why this gives me the same answer:
long long a = 3265917058 >> 24;
std::cout << a << std::endl; //194
long long ip = 3265917058;
long long b = ip >> 24;
std::cout << b << std::endl; //194
but this don't:
long long a = (3265917058 << 16) >> 24;
std::cout << a << std::endl; //240
long long ip = 3265917058;
long long b = (ip << 16) >> 24;
std::cout << b << std::endl; //12757488 - **i want this to be 240 too!**
Update: I want 32bit shift , but how can i 32bit shift a number that is too large for an int variable?
Update2: My answer is to make unsigned int ip. Then everything will be ok.

Your literal constant 3265917058 is an int. Add a LL suffix to get the expected behavio(u)r:
long long a = (3265917058LL << 16) >> 24;

3265917058<<16 both sides are int, so the operation will be done in int (32-bits).
You need 3265917058LL<<16 then the left-side will be a long long and the operation will be done with that width i.e. 64-bits.

To get what you ask for:
long long ip=3265917058;
long long b= (static_cast<unsigned int>(ip)<<16)>> 24;
std::cout<<b<<std::endl; // 240
Note that the result you will get (240) is not portable. Mathematically, the result should be 12757488. The value 240 is due to truncation, and this is not guaranteed to happen. For instance, it doesn't happen on systems where int is 64 bits.

Related

Why round() make my expression give wrong answer? [duplicate]

This question already has answers here:
Cast from unsigned long long to double and vice versa changes the value
(3 answers)
Closed 1 year ago.
I'm currently facing a problem but I don't know why it wrong?
// ll ís long long
ll cnt = 24822089714520516;
cout << "xpow: " << xpow(10LL, 16) << endl;
cout << "cnt: " << cnt << endl;
ll a = xpow(10LL, 16) + cnt - 1;
ll b = round(xpow(10LL, 16)) + cnt - 1;
cout << "cur_num (without round): " << a << endl;
cout << "cur_num (with round): " << b << endl;
with xpow is defined by myself:
ll xpow(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1)
ans *= a;
b >>= 1;
if (b)
a *= a;
};
return ans;
};
When I run my code, I get this log:
xpow: 10000000000000000
cnt: 24822089714520516
cur_num (without round): 34822089714520515
cur_num (with round): 34822089714520516
As you see, my result if I use round is differenced with one when I don't round (smaller than 1 unit)
It may be my computer's problem, but may be no. Can anyone explain why?
Thanks so much!
In many C++ implementations, the long long type is 64 bits long, and the double type is 64 bits long. When this happens, a variable of type double cannot exactly represent all possible long long values, and in particular large long long values might be approximated incorrectly by a double.
Here, round converts your long long to a double, introducing some imprecision.

How would I set a long long to a huge number without a warning?

Right now, I have
long long x = 1 << 60;
cout << x << endl;
and I know that the range for long long can be all the way up to 2^64, but for some reason when I execute the piece of code, it gives me a warning that says "left shift count >= width of type [-Wshift-count-overflow]."
In addition, 0 is printed to the screen, which is obviously not what I wanted.
I tried putting the literal "ll" after it, but I don't know where I should put it:
long long x = (1 << 60)ll;
long long x = (1 << 60ll);
and none of them work
Could anyone please tell me how to fix this? Thanks in advance!
It is a common mistake to expect for this expression:
long long x = 1 << 60;
that type of left side would affect calculations on the right side. It is not, result of 1 << 60 converted to type on the left, but it does not affect calculation of 1 << 60 itself. So proper solution is to change type of 1:
long long x = static_cast<long long >( 1 ) << 60;
or
long long x = 1LL << 60;
or even
auto x = 1LL << 60;

How to correctly truncate integral types

I've asked a similar question but after more research I came across something I cannot understand, and hopefully someone can explain what's causing this behavior:
// We wish to store a integral type, in this case 2 bytes long.
signed short Short = -390;
// In this case, signed short is required to be 2 bytes:
assert(sizeof(Short) == 2);
cout << "Short: " << Short << endl; // output: -390
signed long long Long = Short;
// in this case, signed long long is required to be 8 bytes long
assert(sizeof(Long) == 8);
cout << "Long: " << Long << endl; // output: -390
// enough bytes to store the signed short:
unsigned char Bytes[sizeof(Short)];
// Store Long in the byte array:
for (unsigned int i = 0; i < sizeof(Short); ++i)
Bytes[i] = (Long >> (i * 8)) & 0xff;
// Read the value from the byte array:
signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8);
cout << Long2 << endl; // output: 65146
signed short Short2 = static_cast<signed short>(Long2);
cout << Short2 << endl; // output: -390
output:
-390
-390
65146
-390
Can someone explain what's going on here? Is this undefined behavior? Why?
It is to do with the way negative numbers are stored. A negative number will begin with a 1 in its binary format.
signed long long Long = Short;
This is automatically doing a conversion for you. It isn't just assigning bits from one to the other, it is converting the value resulting in your 64-bit value starting with a 1 to indicate negative, and the rest denoting the 390 in 2s complement (can't be bothered working all the bits out).
signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8);
Now you're only retrieving the end two bytes, which will just represent the 390 magnitude. Your first two bytes will be zeros, so it thinks it is a positive number. It should work out as 2^16 - 390, and it does.
signed short Short2 = static_cast<signed short>(Long2);
This is an overflow. 65146 doesn't fit into a signed, 2-byte integer and so ends out populating the signing bit, making it get interpreted as negative. By no co-incidence, the negative number it represents is -390.

Unsigned long long wrong given value after add

I have two strings to add. Strings is HEX values. I convert strings to long long, add and after I back to string. But this operation no working good.
Code:
unsigned long long FirstNum = std::strtoull(FirstString.c_str(), NULL, 16);
unsigned long long SecondNum = std::strtoull(SecondString.c_str(), NULL, 16);
unsigned long long Num = FirstNum + SecondNum;
std::cout << " " << FirstNum << "\n+ " << SecondNum << "\n= " << Num << "\n\n";
I received
13285923899203179534
+ 8063907133566997305
= 2903086959060625223
Anyone can explain me this magic? How can I fix it?
Back to hex value by
std::stringstream Stream;
Stream << std::hex << Num;
return Stream.str();
All unsigned arithmetic in C (and C++) occurs modulo 2k for some k. In your case, you are getting the result modulo 264, implying that unsigned long long is 64 bits on your platform.
If you want to do arithmetic with integers larger than the largest supported type on your platform, you'll need to use a multiprecision library such as GMP

Bit manipulation and > 32 bit numbers?

I am basically trying to do the following:
c[i] = ((number_to_store << pos) & 0xFF00000000) >> 32;
But this stores 0 in c[i] something not expected. The following works like a charm:
c[i] = ((number_to_store << pos) & 0xFF000000) >> 24;
I am 99% sure the error has something to do with the fact all my variables are unsigned int but here I am requesting 40 bits space.
Can someone please explain the differences between less than or equal to 32 bit and more than 32 bit number, when it's about bit manipulation?
edit: This also gives me 0:
cout << ((((unsigned long)number_to_store << (unsigned long)pos) & (unsigned long)0xFF00000000) >> 32) << endl;
edit 2: The following works:
cout << ((((unsigned long long)number_to_store << (unsigned long long)pos) & (unsigned long long)0xFF00000000) >> 32) << endl;
Lesson learned: never expect long to be larger than int
An unsigned int is 32 bits, if you shift it by 32 bits it will become 0. As you found out, in order to keep bits that are shifted left in your first shift, you must declare the number_to_store as unsigned long long which is 64 bits.