I encountered a strange thing when I was programming under c++. It's about a simple multiplication.
Code:
unsigned __int64 a1 = 255*256*256*256;
unsigned __int64 a2= 255 << 24; // same as the above
cerr()<<"a1 is:"<<a1;
cerr()<<"a2 is:"<<a2;
interestingly the result is:
a1 is: 18446744073692774400
a2 is: 18446744073692774400
whereas it should be:(using calculator confirms)
4278190080
Can anybody tell me how could it be possible?
255*256*256*256
all operands are int you are overflowing int. The overflow of a signed integer is undefined behavior in C and C++.
EDIT:
note that the expression 255 << 24 in your second declaration also invokes undefined behavior if your int type is 32-bit. 255 x (2^24) is 4278190080 which cannot be represented in a 32-bit int (the maximum value is usually 2147483647 on a 32-bit int in two's complement representation).
C and C++ both say for E1 << E2 that if E1 is of a signed type and positive and that E1 x (2^E2) cannot be represented in the type of E1, the program invokes undefined behavior. Here ^ is the mathematical power operator.
Your literals are int. This means that all the operations are actually performed on int, and promptly overflow. This overflowed value, when converted to an unsigned 64bit int, is the value you observe.
It is perhaps worth explaining what happened to produce the number 18446744073692774400. Technically speaking, the expressions you wrote trigger "undefined behavior" and so the compiler could have produced anything as the result; however, assuming int is a 32-bit type, which it almost always is nowadays, you'll get the same "wrong" answer if you write
uint64_t x = (int) (255u*256u*256u*256u);
and that expression does not trigger undefined behavior. (The conversion from unsigned int to int involves implementation-defined behavior, but as nobody has produced a ones-complement or sign-and-magnitude CPU in many years, all implementations you are likely to encounter define it exactly the same way.) I have written the cast in C style because everything I'm saying here applies equally to C and C++.
First off, let's look at the multiplication. I'm writing the right hand side in hex because it's easier to see what's going on that way.
255u * 256u = 0x0000FF00u
255u * 256u * 256u = 0x00FF0000u
255u * 256u * 256u * 256u = 0xFF000000u (= 4278190080)
That last result, 0xFF000000u, has the highest bit of a 32-bit number set. Casting that value to a signed 32-bit type therefore causes it to become negative as-if 232 had been subtracted from it (that's the implementation-defined operation I mentioned above).
(int) (255u*256u*256u*256u) = 0xFF000000 = -16777216
I write the hexadecimal number there, sans u suffix, to emphasize that the bit pattern of the value does not change when you convert it to a signed type; it is only reinterpreted.
Now, when you assign -16777216 to a uint64_t variable, it is back-converted to unsigned as-if by adding 264. (Unlike the unsigned-to-signed conversion, this semantic is prescribed by the standard.) This does change the bit pattern, setting all of the high 32 bits of the number to 1 instead of 0 as you had expected:
(uint64_t) (int) (255u*256u*256u*256u) = 0xFFFFFFFFFF000000u
And if you write 0xFFFFFFFFFF000000 in decimal, you get 18446744073692774400.
As a closing piece of advice, whenever you get an "impossible" integer from C or C++, try printing it out in hexadecimal; it's much easier to see oddities of twos-complement fixed-width arithmetic that way.
The answer is simple -- overflowed.
Here Overflow occurred on int and when you are assigning it to unsigned int64 its converted in to 18446744073692774400 instead of 4278190080
Related
Working through a bug today we realized that we were bit by an implicit type conversion.
int64_t result = intA * intB;
In the case where intA and intB are both positive int, they can overflow at values > 2^31.
I would expect a similar issue with the following code:
int64_t result = (intA * intB) - int64A
But it seems in practice as if we aren't overflowing on the result of intA * intB.
Is that right? If so, why? I read through some of the implicit type conversion rules for C++ to try and understand if it might be because the int64A operand is 64-bits but couldn't find anything conclusive.
I am assuming 32-bit int here.
C++ makes this complicated with the addition of user-defined conversions, but let's assume that user-defined conversions aren't being considered here.
For most arithmetic operations on integers (e.g. not shifts), you get the following conversions (this is from memory...):
Each operand is converted to int if it is narrower1 than int, and all values of its type can be represented by int.
Each operand is then converted to unsigned if it is narrower than unsigned.
Each operand is then converted to the wider type of the two operand types, if one of the types is wider.
If they are the same width, but one is unsigned, then the unsigned type is chosen.
The first two steps are called "integer promotion" and the second two steps are part of the "usual arithmetic conversions".
So, if you want to do 64-bit multiplication,
int x, y;
// Always done with int
int r = x * y; // 32-bit
// These are always done with int64_t
int64_t r = (int64_t)x * y;
int64_t r = x * (int64_t)y;
int64_t r = (int64_t)x * (int64_t)y;
// This is a 32-bit multiplication, you probably don't want this...
// The RESULT is converted to 64 bit
int64_t r = x * y; // 32-bit
// Same thing...
int64_t r = (int64_t)(x * y); // 32-bit
The subtraction happens to the multiplication result, so if the multiplication result is 64-bit, then the subtraction will be done with 64 bits.
HOWEVER: As soon as you overflow with signed integer arithmetic, the results are undefined! This means that if x * y overflows, the compiler is allowed to do anything it wants. Maybe it gives you the 64-bit result. Maybe it crashes. Maybe it formats your hard drive. Maybe things behave oddly in your program.
In practice this is "bounded undefined behavior" so it probably will just cause you to scratch your head and curse rather than crash your program outright.
1: "Narrower" is not technically the term used in the standard.
Consider the following code:
int32_t x = -2;
cout << uint64_t(x) << endl;
The cast in the second line contains basically two atomic steps. The increase in bitwidth from 32 bits to 64 bits and the change of interpretation from signed to unsigned. If one compiles this with g++ and executes, one gets 18446744073709551614. This suggests that the increase in bitwidth is processed first (as a signed extension) and the change in signed/unsigned interpretation thereafter, i.e. that the code above is equivalent to writing:
int32_t x = -2;
cout << uint64_t(int64_t(x)) << endl;
What confuses me that one could also first interpret x as an unsigned 32-bit bitvector first and then zero-extend it to 64-bit, i.e.
int32_t x = -2;
cout << uint64_t(uint32_t(x)) << endl;
This would yield 4294967294. Would someone please confirm that the behavior of g++ is required by the standard and is not implementation defined? I would be most excited if you could refer me to the norm in the standard that actually concerns the issue at hand. I tried to do so but failed bitterly.
Thanks in advance!
You are looking for Standard section 4.7. In particular, paragraph 2 says:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).
In the given example, we have that 18446744073709551614 = -2 mod 264.
As said by #aschepler, standard 4.7 §2 (Integral conversions) ensures that the result will be least unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the unsigned type)
So in your case, it will be 0xFFFFFFFFFFFFFFFE == 18446744073709551614
But this is a one step conversion as specified by the standard (what compiler actually does is out of scope)
If you want first unsigned conversion to uint32_t and then conversion to uint64_t, you have to specify 2 conversions : static_cast<uint64_t>(static_cast<uint32_t>(-2))
Per 4.7 §2, first will give 0xFFFFFFFE = 4294967294 but as this number is already a valid uint64_t it is unchanged by the second conversion.
What you observed is required by the standard and will be observable on any conformant compiler (provided uint32_t and uint64_t are defined, because this part is not required ...)
This is an old question but I recently came into this problem. I was using char, which happened to be signed in my computer. I wanted to multiply two values by
char a, b;
uint16 ans = uint16(a) * uint16(b);
However, because of the conversion, when a < 0, the answer is wrong.
Since the signedness of char is implementation-dependent, maybe we should use uint8 instead of char whenever possible.
I have a weird bug/error/self stupidity concern. I'm developing a small application in C, and I'm using Visual Studio 2010 SP1. The offending code:
uint64_t sum_squared_X = 65535*65535*64;
int64_t sum_squared_Y = 65535*65535*64;
When debugging, I get these results:
sum_squared_X = 18446744073701163072;
sum_squared_Y = -8388544;
Question is, why? An uint64_t has a maximum value of 2^64-1 or 18446744073709551615, and an int64_t a maximum value of 2^63-1 or 9223372036854775807.
65535*65535*64 = 274869518400, which is lower than both maximums. Then why am I getting these results?
I'm completely lost here, some help would be appreciated.
Short answer: 65535 is multiplied by 65535 using 32-big signed arithmetic, producing -131,071. This is then multiplied by -64 and converted to uint64_t (creating a larger positive value due to wrapping) or int64_t (preserving the result of multiplying -131,071 by 64).
Long answer:
The type of an unsuffixed integer decimal constant depends on its value. It is the first of this list that can represent its value: int, long int, long long int. (Adding a suffix or using an octal or hexadecimal constant changes the list.) Because these types depend on the C implementation, the behavior depends on the C implementation.
It is likely that, in your machine, int is 32 bits. Therefore, the type of “65535” is int, and so is the type of “64”.
Your expression starts with “65535*65535”. This multiplies 65,535 by 65,535. The mathematical result is 4,924,836,225 (in hex, 0xfffe0001). With a 32-bit signed int, this overflows the representable values. This is undefined behavior in the C standard. What commonly happens in many implementations is that the value “wraps around” from 231-1 (the highest representable value) to -231 (the lowest representable value). Another view of the same behavior is that the bits of the mathematical result, 0xfffe0001, are interpreted as the encoding of a 32-bit signed int. In two’s complement, 0xffffe0001 is -131,071.
Then your expression multiplies by 64. -131,071*64 does not overflow; the result is -8,388,544 (with encoding 0xff800040).
Finally, you use the result to initialize a uint64_t or int64_t object. This initialization causes a conversion to the destination type.
The int64_t conversion is straightforward; the input to the conversion is -8,388,544, and this is exactly representable in int64_t, so the result is -8,388,544, which the compiler likely implements simply by extending the sign bit (producing the encoding 0xffffffffff800040).
The uint64_t conversion is troublesome, because -8,388,544 cannot be represented in a uint64_t. According to the 1999 C standard, 6.3.1.3 2, “the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.” For uint64_t, “one more than the maximum value that can be represented in the new type” is 264. So the result is -8,388,544 + 264, which is 18,446,744,073,701,163,072. This also has the encoding 0xffffffffff800040.
For conversion from a narrower width to a wider width, this operation of adding one more than maximum value is equivalent to copying the sign bit of the old type to all higher bits in the new type (sign extension). For conversion from a wider width to a narrower width, it is equivalent to discarding the high bits. In either case, the result is the residue modulo 2n, where n is the number of bits in the new type.
When I compile your example, I clearly get an integer constant overflow warning for each of those lines. This is because the right side, the constants, is usually stored in a basic integer. You have to change the storage of those values to keep an overflow condition from happening. To fix this, do the following instead:
uint64_t sum_squared_X = (uint64_t)65535*65535*64;
int64_t sum_squared_Y = (uint64_t)65535*65535*64;
Read more here
Hi I am new in here so please let me know if anything is wrong and I will try to better the next time .
I am trying to understand how underflow and overflow works in C++ .My understanding is if a variable's range is exceeded it will start from the other end of the range . Thus if minimum of short is -32768 and if we do a -1 to it the new value should be SHRT_MAX .(32767)
Here is my code:
#include<iostream.h>
#include<limits.h>
#include<conio.h>
int main ( void )
{
int testpositive =INT_MIN ;
short testnegative = SHRT_MIN ;
cout<< SHRT_MIN<<"\n";
cout << testnegative-1<<"\n";
cout << INT_MIN << "\n";
cout << testpositive-1 << "\n";
cout<<testpositive-2;
getch();
return 0;
}
The exact behavior on overflow/underflow is only specified for unsigned types.
Unsigned integers shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer.
Source: Draft N3690 §3.9.1 sentence 4
This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting
unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the
resulting unsigned integer type.
Source: Draft N3690 Note 47 for §3.9.1
For normal signed integer types instead the C++ standard simply says than anything can happen.
If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined
Source: Draft N3690 §5 sentence 4
If we're talking about x86 processor (or most other modern processors) indeed the behavior is exactly what you describe and for the CPU there is no difference between a signed value or an unsigned value (there are signed and unsigned operations, but the value themselves are just bits).
Note that compilers can assume (and most modern optimizing compilers actually DO assume) that no signed integer overflow can occur in a correct program and for example in code like:
int do_something();
int do_something_else();
void foo() {
int x = do_something();
int y = x + 1;
if (x < y) {
do_something();
} else {
do_something_else();
}
}
a compiler is free to skip the test and the else branch in the generated code completely because in a valid program a signed int x is always less than x+1 (as signed overflow cannot be considered valid behavior).
If you replace int with unsigned int however the compiler must generate code for the test and for the else branch because for unsigned types it's possible that x > x+1.
For example clang compiles the code for foo to
foo(): # #foo()
push rax
call do_something()
pop rax
jmp do_something() # TAILCALL
where you can see that the ode just calls do_something twice (except for the strange handling of rax) and no mention of do_something_else is actually present. More or less the same code is generated by gcc.
Signed overflows are undefined behavior in C++.
For example:
INT_MIN - 1
-INT_MIN
are expressions that invoke undefined behavior.
SHRT_MIN - 1 and -SHRT_MIN are not undefined behavior in an environment with 16-bit short and 32-bit int because with integer promotions the operand is promoted to int first. In an environment with 16-bit short and int, these expressions are also undefined behavior.
Typically yes. But since this is C++, and C++ is regulated by the C++ standard, you must know that overflows are undefined behavior.
Although what you stated probably applies on most platforms, it's in no way guaranteed, so don't rely on it.
The new value need not be SHRT_MAX it is undefined.
I want signed integers to overflow when they become too big. How do I achieve that without using the next biggest datatype (or when I am already at int128_t)?
For example using 8bit integers 19*12 is commonly 260, but I want the result 1 11 10 01 00 with the 9th bit cut off, thus -27.
Signed overflow is undefined in C, and that's for real.
One solution follows:
signed_result = (unsigned int)one_argument + (unsigned int)other_argument;
The above solution involves implementation-defined behavior in the final conversion from unsigned to int but do not invoke undefined behavior. With most compilation platforms' implementation-defined choices, the result is exactly the two's complement result that you expect.
Finally, an optimizing compiler for one of the numerous platforms on which implementation-defined choices force the compiler to give you the behavior you expect will compile the above code to the obvious assembly instruction.
Alternately, if you are using gcc, then the options -fwrapv/-fno-strict-overflow may be exactly what you want. They provide an additional guarantee with respect to the standard that signed overflows wrap around. I'm not sure about the difference between the two.
Signed integer overflow is undefined according to both C and C++ standards. There's no way to accomplish what you want without a specific platform in mind.
It is possible to do this in a correct standard C manner, so long as you have access to an unsigned type that is of the same width as your signed type (that is, has one more value bit). To demonstrate with int64_t:
int64_t mult_wrap_2scomp(int64_t a, int64_t b)
{
uint64_t result = (uint64_t)a * (uint64_t)b;
if (result > INT64_MAX)
return (int64_t)(result - INT64_MAX - 1) - INT64_MAX - 1;
else
return (int64_t)result;
}
This does not produce any problematic intermediate results.
You could create an objective wrapper around int, but that would involve quite a lot of overhead code.
Assuming two's complement signed integer arithmetic (which is a reasonable assumption these days), for addition and subtraction, just cast to unsigned to do the calculation. For multiplication and division, ensure the operands are positive, cast to unsigned, calculate and adjust the signs.
It sounds like you want to do unsinged integer arithmetic, then stuff the result into a signed integer:
unsigned char a = 19;
unsigned char b = 12;
signed char c = (signed char)(a*b);
should give you what you're looking for. Let us know if it doesn't.
Use bigger datatypes. With GMP you will have all the space you probably need.