Arithmetic result for the same expression lead to different outcomes depending on wether I define an integer in one line or I use several steps:
int main() {
unsigned long long veryBigIntOneLine = ((255*256+255)*256+255)*256+255;
unsigned long long veryBigInt = 255;
veryBigInt *= 256;
veryBigInt += 255;
veryBigInt *= 256;
veryBigInt += 255;
veryBigInt *= 256;
veryBigInt += 255;
unsigned long long veryBigIntParanthesis = (((((255*256)+255)*256)+255)*256)+255;
unsigned long long fourthInt = 256;
fourthInt *= 256;
fourthInt *= 256;
fourthInt *= 256;
--fourthInt;
cout << "veryBigIntOneLine: " << veryBigIntOneLine << endl;
cout << "veryBigInt: " << veryBigInt << endl;
cout << "veryBigIntParanthesis: " << veryBigIntParanthesis << endl;
cout << "fourthInt: " << fourthInt << endl;
return 0;
}
they should all describe the same number, 256^4-1 (or 2^32-1), but the outcome is different.
veryBigIntOneLine: 18446744073709551615
veryBigInt: 4294967295
veryBigIntParanthesis: 18446744073709551615
fourthInt: 4294967295
4294967295 is the expected answer (as it is given for all four expressions by the Google calculator).
Also 18446744073709551615 is probably not an exact result of what is computed as I get an overflow warning at compilation time for both one line expressions (even when I tried with type __int128). It is actually 2^64-1, which is the max value for unsigned long long with my compiler (veryBigIntOneLine+1 gives 0).
Initialization code ((255*256+255)*256+255)*256+255 suffers from signed integer overflow which is Undefined Behavior, as well as from implicit conversion of signed int to unsigned. While step-by step calculations avoid those problems because right hand operand is implicitly converted to unsigned long long.
Simply using appropriate literals will fix those issues:
unsigned long long veryBigIntOneLine{ ((255ull*256ull+255ull)*256ull+255ull)*256ull+255ull}; // 4294967295
This is because you are not using unsigned long long literals. If you want literals to match your definitions you need to use:
255ULL + 256ULL * 255ULL + ...
The ULL is very important if you create numbers that are 64 bits. In C, without the suffix a number may be 64, 32 or even just 16 bits (even bytes on some CRAY where 64 bits. That also means your code would have worked just find on one of those CRAY systems.)
Related
On my application, I receive two signed 32-bit int and I have to store them. I have to create a sort of counter and I don't know when it will be reset, but I'll receive big values and frequently. Beacause of that, in order to store these values, I decided to use two unsigned 64-bit int.
The following could be a simple version of the counter.
struct Counter
{
unsigned int elementNr;
unsigned __int64 totalLen1;
unsigned __int64 totalLen2;
void UpdateCounter(int len1, int len2)
{
if(len1 > 0 && len2 > 0)
{
++elementNr;
totalLen1 += len1;
totalLen2 += len2;
}
}
}
I know that if a smaller type is casted to a bigger one (e.g. int to long) there should be no issues. However, passing from 32 bit rappresentation to 64 bit rappresentation and from signed to unsigned at the same time, is something new for me.
Reading around, I undertood that len1 should be expanded from 32 bit to 64 bit and then applied sign extension. Because the unsigned int and signen int have the same rank (Section 4.13), the latter should be converted.
If len1 stores a negative value, passing from signed to unsigned will return a wrong value, this is why I check the positivy at the beginning of the function. However, for positive values, there
should be no issues I think.
For clarity I could revrite UpdateCounter(int len1, int len2) like this
void UpdateCounter(int len1, int len2)
{
if(len1 > 0 && len2 > 0)
{
++elementNr;
__int64 tmp = len1;
totalLen1 += static_cast<unsigned __int64>(tmp);
tmp = len2;
totalLen2 += static_cast<unsigned __int64>(tmp);
}
}
Might there be some side effects that I have not considered.
Is there another better and safer way to do that?
A little background, just for reference: binary operators such arithmetic addition work on operands of the same type (the specific CPU instruction to which is translated depends on the number representation that must be the same for both instruction operands).
When you write something like this (using fixed width integer types to be explicit):
int32_t a = <some value>;
uint64_t sum = 0;
sum += a;
As you already know this involves an implicit conversion, more specifically an
integral promotion according to integer conversion rank.
So the expression sum += a; is equivalent to sum += static_cast<uint64_t>(a);, so a is promoted having the lesser rank.
Let's see what happens in this example:
int32_t a = 60;
uint64_t sum = 100;
sum += static_cast<uint64_t>(a);
std::cout << "a=" << static_cast<uint64_t>(a) << " sum=" << sum << '\n';
The output is:
a=60 sum=160
So all is all ok as expected. Let's se what happens adding a negative number:
int32_t a = -60;
uint64_t sum = 100;
sum += static_cast<uint64_t>(a);
std::cout << "a=" << static_cast<uint64_t>(a) << " sum=" << sum << '\n';
The output is:
a=18446744073709551556 sum=40
The result is 40 as expected: this relies on the two's complement integer representation (note: unsigned integer overflow is not undefined behaviour) and all is ok, of course as long as you ensure that the sum does not become negative.
Coming back to your question you won't have any surprises if you always add positive numbers or at least ensuring that sum will never be negative... until you reach the maximum representable value std::numeric_limits<uint64_t>::max() (2^64-1 = 18446744073709551615 ~ 1.8E19).
If you continue to add numbers indefinitely sooner or later you'll reach that limit (this is valid also for your counter elementNr).
You'll overflow the 64 bit unsigned integer by adding 2^31-1 (2147483647) every millisecond for approximately three months, so in this case it may be advisable to check:
#include <limits>
//...
void UpdateCounter(const int32_t len1, const int32_t len2)
{
if( len1>0 )
{
if( static_cast<decltype(totalLen1)>(len1) <= std::numeric_limits<decltype(totalLen1)>::max()-totalLen1 )
{
totalLen1 += len1;
}
else
{// Would overflow!!
// Do something
}
}
}
When I have to accumulate numbers and I don't have particular requirements about accuracy I often use double because the maximum representable value is incredibly high (std::numeric_limits<double>::max() 1.79769E+308) and to reach overflow I would need to add 2^32-1=4294967295 every picoseconds for 1E+279 years.
I became a little bit confuse about assigning a small number to a big data-type variable, for example in my code (checkout online) :
#include <iostream>
int main()
{
unsigned long long num = 5000000000;
unsigned long long num2 = static_cast<unsigned long long>(5000000) * static_cast<unsigned long long>(1000);
unsigned long long num3 = 5000000 * 1000UL; // Casting 1000 to long data-type
unsigned long long num4 = 5000000 * 1000;
std::cout << num << std::endl << num2 << std::endl << num3 << std::endl << num4;
return 0;
}
The output is
5000000000
5000000000
5000000000
705032704
I know about literal casting and static_cast feature in c++ and also about the compiler behavior that always casting with the biggest data-type in a mathematical statement.
But the problem is here that why the result of statement unsigned long long num4 = 5000000 * 1000; is the number 705032704 and not 5000000000? BTW i know when i cast it like 5000000 * 1000UL; it gives me 5000000000 (because it cast to largest data-type).
Why the unsigned long long num4 = 5000000 * 1000; statement dont casting automatically to unsigned long long data-type without using casting directly?
Where the number 705032704 come from when 5000000 * 1000 calculated?
Regards!
Your line unsigned long long num4 = 5000000 * 1000; consists of three independent parts which are evaluated separately.
The right-hand-side is evaluated as int because all the operands are int. The result is not what you expect because of an integer overflow.
The left-hand-side makes space for an unsigned long long.
The assignment copies the (unexpected) result from the right-hand-side into the space allocated for the variable.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
int divided by unsigned int causing rollover
Hi I am doing the following:
struct coord{
int col;
};
int main(int argc, char* argv[]) {
coord c;
c.col = 0;
std::vector<coord> v;
for(int i = 0; i < 5; i++){
v.push_back(coord());
}
c.col += -13;
cout << " c.col is " << c.col << endl;
cout << " v size is " << v.size() << endl;
c.col /= v.size();
cout << c.col << endl;
}
and I get the following output:
c.col is -13
v size is 5
858993456
However, if I change the division line to c.col /= ((int)v.size()); I get the expected output:
c.col is -13
v size is 5
-2
Why is this?
This is a consequence of v.size() being unsigned.
See int divided by unsigned int causing rollover
The problem is that vector< ... >::size() returns size_t, which is a typedef for an unigned integer type. Obviously the problem arises when you divide a signed integer with an unsigned one.
std::vector::size returns a size_t which is an unsigned integer type, usually unsigned int. When you perform an arithmetic operation with an int and an unsigned int, the int operand is converted to unsigned int to perform the operation. In this case, -13 is converted to unsigned int, which is some number close to 4294967295 (FFFFFFFF in hexadecimal). And then that is divided by 5.
As stated, the reason is that a signed / unsigned division is performed by first converting the signed value to unsigned.
So, you need to prevent this by manually converting the unsigned value to a signed type.
There's a risk that v.size() could be too big for an int. But since the dividend does fit in an int, the result of the division is fairly boring when the divisor is bigger than that. So assuming 2's complement and no padding bits:
if (v.size() <= INT_MAX) {
c.col /= int(v.size());
} else if (c.col == INT_MIN && v.size() - 1 == INT_MAX) {
c.col = -1;
} else {
c.col = (-1 / 2);
}
In C++03, it's implementation-defined whether a negative value divided by a larger positive value is 0 or -1, hence the funny (-1 / 2). In C++11 you can just use 0.
To cover other representations than 2's complement you need to deal with the special cases differently.
I scan through the byte representation of an int variable and get somewhat unexpected result.
If I do
int a = 127;
cout << (unsigned int) *((char *)&a);
I get 127 as expected. If I do
int a = 256;
cout << (unsigned int) *((char *)&a + 1);
I get 1 as expected. But if I do
int a = 128;
cout << (unsigned int) *((char *)&a);
I have 4294967168 which is, well… quite fancy.
The question is: is there a way to get 128 when looking at first byte of an int variable which value is 128?
For the same reason that (unsigned int)(char)128 is 4294967168: char is signed by default on most commonly used systems. 128 cannot fit in a signed 8-bit quantity, so when you cast it to char, you get -128 (0x80 in hex).
Then, when you cast -128 to an unsigned int, you get 232 - 128, which is 4294967168.
If you want to get +128, then use an unsigned char instead of char.
char is signed here, so in your second example, *((char *)&a + 1) = ((char)256 +1) = (0+1) = 1, which is encoded as 0b00000000000000000000000000000001, so becomes 1 as an unsigned int.
In your third example, *((char *)&a) = (char)128 = (char)-127, which is encoded as 0b10000000000000000000000000000000, i.e., 2<<31, which is 4294967168
As the comments have pointed out, it looks like what's happening here is that you are running into an oddity of twos complement. In your last cast, since you are not using an unsigned char, the highest-order bit of the byte is being used to indicate positive or negative values. You then only have 7 bits out of the full 8 to represent your value, giving you a range of 0-127 for positive numbers (-128-127 overall).
If you exceed this range, then it wraps, and you get -128, which when casted back to an unsigned int will result in that abnormally large value.
int a = 128;
cout << (unsigned int) *((unsigned char *)&a);
Also all of your code is dependent on running on a little endian machine.
Here's how you should probably be doing these things:
int a = 127;
cout << (unsigned)(unsigned char)(0xFF & a);
int a = 256;
cout << (unsigned)(unsigned char)(0xFF & (a>>8));
int a = 128;
cout << (unsigned)(unsigned char)(0xFF & a);
Why this code does not write 0 as a last element but 18446744073709551615?
(compiled with g++)
#include <iostream>
using namespace std;
int main(){
unsigned long long x = (unsigned long long) (-1);
for(int i=0; i <= 64; i++)
cout << i << " " << (x >> i) << endl;
cout << (x >> 64) << endl;
return 0;
}
When you shift a value by more bits than word size, it usually gets shifted by mod word-size. Basically, shifting it by 64 means shifting by 0 bits which is equal to no shifting at all. You shouldn't rely on this though as it's not defined by the standard and it can be different on different architectures.
Shifting a number a number of bits that is equal to or larger than its width is undefined behavior. You can only safely shift a 64-bit integer between 0 and 63 positions.
This warning from the compiler should be a hint:
"warning: right shift count >= width of type"
This results in undefined behavior:
http://sourcefrog.net/weblog/software/languages/C/bitshift.html
well, you are shifting one too many times. you are shifting from 0 to 64 inclusive which is a total of 65 times. You generally want:
for(int i=0; i < 64; i++)
....
You overflow the shift. If you've noticed, GCC even warns you:
warning: right shift count >= width of type
How come? You include 64 as a valid shift, which is an undefined behavior.
counting from 0 to 64 there are 65 numbers (0 included). 0 being the first bit (much like arrays).
#include <iostream>
using namespace std;
int main(){
unsigned long long x = (unsigned long long) (-1);
for(int i=0; i < 64; i++)
cout << i << " " << (x >> i) << endl;
cout << (x >> 63) << endl;
return 0;
}
Will produce the output you'd expect.
You can use:
static inline pack_t lshift_fix64(pack_t shiftee, short_idx_t shifter){
return (shiftee << shifter) & (-(shifter < 64));
}
for such a trick,
(-(shifter < 64)) == 0xffff ffff ffff ffff
if shifter < 64 and
(-(shifter < 64)) == 0x0
otherwise.
I get:
test.c:8: warning: right shift count >= width of type
so perhaps it's undefined behavior?
The bit pattern of -1 looks like 0xFFFFFFFFFFFFFFFF in hex, for 64 bit types. Thus if you print it as an unsigned variable you will see the largest value an unsigned 64 bit variable can hold, i.e. 18446744073709551615.
When bit shifting we don't care what a value means in this case, i.e. it doesn't matter if the variable is signed or unsigned it is treated the same way (shifting all bits one step to the right in this case).
Another trap for the unwary: I know this is an old thread, but I came here looking for help. I got caught out on a 64 bit machine using 1<<k when I meant 1L<<k; no help from the compiler in this case :(