Is a negative integer summed with a greater unsigned integer promoted to unsigned int?
After getting advised to read "C++ Primer 5 ed by Stanley B. Lipman" I don't understand this:
Page 66. "Expressions Involving Unsigned Types"
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
He said:
In the second expression, the int value -42 is converted to unsigned before the addition is done. Converting a negative number to unsigned behaves exactly as if we had attempted to assign that negative value to an unsigned object. The value “wraps around” as described above.
But if I do something like this:
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
As you can see -10
is not converted to unsigned int
. Does this mean a comparison occurs before promoting a signed integer
to an unsigned integer
?
c++ unsigned-integer
add a comment |
After getting advised to read "C++ Primer 5 ed by Stanley B. Lipman" I don't understand this:
Page 66. "Expressions Involving Unsigned Types"
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
He said:
In the second expression, the int value -42 is converted to unsigned before the addition is done. Converting a negative number to unsigned behaves exactly as if we had attempted to assign that negative value to an unsigned object. The value “wraps around” as described above.
But if I do something like this:
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
As you can see -10
is not converted to unsigned int
. Does this mean a comparison occurs before promoting a signed integer
to an unsigned integer
?
c++ unsigned-integer
16
As you can see -10 is not converted to unsigned int.
It is.
– tkausl
Jan 14 at 22:28
2
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
2
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Thank you all guys. You make it clear for me now.
– Alex24
yesterday
add a comment |
After getting advised to read "C++ Primer 5 ed by Stanley B. Lipman" I don't understand this:
Page 66. "Expressions Involving Unsigned Types"
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
He said:
In the second expression, the int value -42 is converted to unsigned before the addition is done. Converting a negative number to unsigned behaves exactly as if we had attempted to assign that negative value to an unsigned object. The value “wraps around” as described above.
But if I do something like this:
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
As you can see -10
is not converted to unsigned int
. Does this mean a comparison occurs before promoting a signed integer
to an unsigned integer
?
c++ unsigned-integer
After getting advised to read "C++ Primer 5 ed by Stanley B. Lipman" I don't understand this:
Page 66. "Expressions Involving Unsigned Types"
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
He said:
In the second expression, the int value -42 is converted to unsigned before the addition is done. Converting a negative number to unsigned behaves exactly as if we had attempted to assign that negative value to an unsigned object. The value “wraps around” as described above.
But if I do something like this:
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
As you can see -10
is not converted to unsigned int
. Does this mean a comparison occurs before promoting a signed integer
to an unsigned integer
?
c++ unsigned-integer
c++ unsigned-integer
edited 2 days ago
Lightness Races in Orbit
287k51466788
287k51466788
asked Jan 14 at 22:26
Alex24Alex24
1508
1508
16
As you can see -10 is not converted to unsigned int.
It is.
– tkausl
Jan 14 at 22:28
2
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
2
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Thank you all guys. You make it clear for me now.
– Alex24
yesterday
add a comment |
16
As you can see -10 is not converted to unsigned int.
It is.
– tkausl
Jan 14 at 22:28
2
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
2
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Thank you all guys. You make it clear for me now.
– Alex24
yesterday
16
16
As you can see -10 is not converted to unsigned int.
It is.– tkausl
Jan 14 at 22:28
As you can see -10 is not converted to unsigned int.
It is.– tkausl
Jan 14 at 22:28
2
2
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
2
2
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Thank you all guys. You make it clear for me now.
– Alex24
yesterday
Thank you all guys. You make it clear for me now.
– Alex24
yesterday
add a comment |
5 Answers
5
active
oldest
votes
-10
is being converted to a unsigned integer with a very large value, the reason you get a small number is that the addition wraps you back around. With 32 bit unsigned integers -10
is the same as 4294967286
. When you add 42 to that you get 4294967328
, but the max value is 4294967296
, so we have to take 4294967328
modulo 4294967296
and we get 32
.
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Whyshort
andchar
are not promoted tounsigned
?
– Alex24
yesterday
1
@Alex24 You're welcome.short
andchar
get promoted toint
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have aunsigned char
orunsigned short
and it has the same size asint
. Then it would be promoted to anunsigned int
.
– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
add a comment |
Well, I guess this is an exception to "two wrongs don't make a right" :)
What is happening is that there are actually two wrap arounds (unsigned overflows) under the hood and the final result is ends up being mathematically correct.
First,
i
is converted to unsigned and as per wrap around behavior the value isstd::numeric_limits<unsigned>::max() - 9
.When this value is summed with
u
the mathematical result would bestd::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33
which is an overflow and we get another wrap around. So the final result is32
.
As a general rule in an arithmetic expression if you only have unsigned overflows (no matter how many) and if the final mathematical result is representable in the expression data type, then the value of the expression will be the mathematically correct one. This is a consequence of the fact that unsigned integers in C++ obey the laws of arithmetic modulo 2n (see bellow).
Important notice. According to C++ unsigned arithmetic does not overflow:
§6.9.1 Fundamental types [basic.fundamental]
- Unsigned integers shall obey the laws of arithmetic modulo 2n where n
is the number of bits in the value representation of that particular
size of integer 49
49) 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.
I will however leave "overflow" in my answer to signify values that cannot be represented in regular arithmetic.
Also what we colloquially call "wrap around" is in fact just the arithmetic modulo nature of the unsigned integers. I will however use "wrap around" also because it is easier to understand.
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
|
show 13 more comments
i
is in fact promoted to unsigned int
.
Unsigned integers in C and C++ implement arithmetic in ℤ / 2nℤ, where n is the number of bits in the unsigned integer type. Thus we get
[42] + [-10] ≡ [42] + [2n - 10] ≡ [2n + 32] ≡ [32],
with [x] denoting the equivalence class of x in ℤ / 2nℤ.
Of course, the intermediate step of picking only non-negative representatives of each equivalence class, while it formally occurs, is not necessary to explain the result; the immediate
[42] + [-10] ≡ [32]
would also be correct.
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
@JAD Quotient ring.
– user202729
2 days ago
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
|
show 2 more comments
"In the second expression, the int value -42 is converted to unsigned before the addition is done"
yes this is true
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Supposing we are in 32 bits (that change nothing in 64b, this is just to explain) this is computed as 42u + ((unsigned) -10)
so 42u + 4294967286u
and the result is 4294967328u truncated in 32 bits so 32. All was done in unsigned
add a comment |
This is part of what is wonderful about 2's complement representation. The processor doesn't know or care if a number is signed or unsigned, the operations are the same. In both cases, the calculation is correct. It's only how the binary number is interpreted after the fact, when printing, that is actually matters (there may be other cases, as with comparison operators)
-10 in 32BIT binary is FFFFFFF6
42 IN 32bit BINARY is 0000002A
Adding them together, it doesn't matter to the processor if they are signed or unsigned, the result is: 100000020. In 32bit, the 1 at the start will be placed in the overflow register, and in c++ is just disappears. You get 0x20 as the result, which is 32.
In the first case, it is basically the same:
-42 in 32BIT binary is FFFFFFD6
10 IN 32bit binary is 0000000A
Add those together and get FFFFFFE0
FFFFFFE0 as a signed int is -32 (decimal). The calculation is correct! But, because it is being PRINTED as an unsigned, it shows up as 4294967264. It's about interpreting the result.
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byteINTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.
– Arne Vogel
2 days ago
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54190113%2fis-a-negative-integer-summed-with-a-greater-unsigned-integer-promoted-to-unsigne%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
-10
is being converted to a unsigned integer with a very large value, the reason you get a small number is that the addition wraps you back around. With 32 bit unsigned integers -10
is the same as 4294967286
. When you add 42 to that you get 4294967328
, but the max value is 4294967296
, so we have to take 4294967328
modulo 4294967296
and we get 32
.
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Whyshort
andchar
are not promoted tounsigned
?
– Alex24
yesterday
1
@Alex24 You're welcome.short
andchar
get promoted toint
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have aunsigned char
orunsigned short
and it has the same size asint
. Then it would be promoted to anunsigned int
.
– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
add a comment |
-10
is being converted to a unsigned integer with a very large value, the reason you get a small number is that the addition wraps you back around. With 32 bit unsigned integers -10
is the same as 4294967286
. When you add 42 to that you get 4294967328
, but the max value is 4294967296
, so we have to take 4294967328
modulo 4294967296
and we get 32
.
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Whyshort
andchar
are not promoted tounsigned
?
– Alex24
yesterday
1
@Alex24 You're welcome.short
andchar
get promoted toint
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have aunsigned char
orunsigned short
and it has the same size asint
. Then it would be promoted to anunsigned int
.
– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
add a comment |
-10
is being converted to a unsigned integer with a very large value, the reason you get a small number is that the addition wraps you back around. With 32 bit unsigned integers -10
is the same as 4294967286
. When you add 42 to that you get 4294967328
, but the max value is 4294967296
, so we have to take 4294967328
modulo 4294967296
and we get 32
.
-10
is being converted to a unsigned integer with a very large value, the reason you get a small number is that the addition wraps you back around. With 32 bit unsigned integers -10
is the same as 4294967286
. When you add 42 to that you get 4294967328
, but the max value is 4294967296
, so we have to take 4294967328
modulo 4294967296
and we get 32
.
edited Jan 14 at 22:55
answered Jan 14 at 22:36
NathanOliverNathanOliver
89.1k15120187
89.1k15120187
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Whyshort
andchar
are not promoted tounsigned
?
– Alex24
yesterday
1
@Alex24 You're welcome.short
andchar
get promoted toint
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have aunsigned char
orunsigned short
and it has the same size asint
. Then it would be promoted to anunsigned int
.
– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
add a comment |
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Whyshort
andchar
are not promoted tounsigned
?
– Alex24
yesterday
1
@Alex24 You're welcome.short
andchar
get promoted toint
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have aunsigned char
orunsigned short
and it has the same size asint
. Then it would be promoted to anunsigned int
.
– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
What I find interesting with modulo arithmetic is that by "convoluted" means, you get the same answer as regular arithmetic. This is one reason to justify wrapping behavior for overflow handling.
– Matthieu M.
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
@MatthieuM. The "convolution" only happens when you think of unsigned integers as numbers. The fact that adding a number from the equivalence class of 42 to a number from the equivalence class of -10 yields a value from the equivalence class of 32 is no less intuitive than the signed result IMO.
– Baum mit Augen
2 days ago
So easy and simple to understand thank you. One thing: Why
short
and char
are not promoted to unsigned
?– Alex24
yesterday
So easy and simple to understand thank you. One thing: Why
short
and char
are not promoted to unsigned
?– Alex24
yesterday
1
1
@Alex24 You're welcome.
short
and char
get promoted to int
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have a unsigned char
or unsigned short
and it has the same size as int
. Then it would be promoted to an unsigned int
.– NathanOliver
yesterday
@Alex24 You're welcome.
short
and char
get promoted to int
as that is the smallest built in type that the mathematical operators use. The only time where that could be different is when you have a unsigned char
or unsigned short
and it has the same size as int
. Then it would be promoted to an unsigned int
.– NathanOliver
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
@NathanOliver: Perfect! thank you again. Really got your point.
– Alex24
yesterday
add a comment |
Well, I guess this is an exception to "two wrongs don't make a right" :)
What is happening is that there are actually two wrap arounds (unsigned overflows) under the hood and the final result is ends up being mathematically correct.
First,
i
is converted to unsigned and as per wrap around behavior the value isstd::numeric_limits<unsigned>::max() - 9
.When this value is summed with
u
the mathematical result would bestd::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33
which is an overflow and we get another wrap around. So the final result is32
.
As a general rule in an arithmetic expression if you only have unsigned overflows (no matter how many) and if the final mathematical result is representable in the expression data type, then the value of the expression will be the mathematically correct one. This is a consequence of the fact that unsigned integers in C++ obey the laws of arithmetic modulo 2n (see bellow).
Important notice. According to C++ unsigned arithmetic does not overflow:
§6.9.1 Fundamental types [basic.fundamental]
- Unsigned integers shall obey the laws of arithmetic modulo 2n where n
is the number of bits in the value representation of that particular
size of integer 49
49) 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.
I will however leave "overflow" in my answer to signify values that cannot be represented in regular arithmetic.
Also what we colloquially call "wrap around" is in fact just the arithmetic modulo nature of the unsigned integers. I will however use "wrap around" also because it is easier to understand.
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
|
show 13 more comments
Well, I guess this is an exception to "two wrongs don't make a right" :)
What is happening is that there are actually two wrap arounds (unsigned overflows) under the hood and the final result is ends up being mathematically correct.
First,
i
is converted to unsigned and as per wrap around behavior the value isstd::numeric_limits<unsigned>::max() - 9
.When this value is summed with
u
the mathematical result would bestd::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33
which is an overflow and we get another wrap around. So the final result is32
.
As a general rule in an arithmetic expression if you only have unsigned overflows (no matter how many) and if the final mathematical result is representable in the expression data type, then the value of the expression will be the mathematically correct one. This is a consequence of the fact that unsigned integers in C++ obey the laws of arithmetic modulo 2n (see bellow).
Important notice. According to C++ unsigned arithmetic does not overflow:
§6.9.1 Fundamental types [basic.fundamental]
- Unsigned integers shall obey the laws of arithmetic modulo 2n where n
is the number of bits in the value representation of that particular
size of integer 49
49) 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.
I will however leave "overflow" in my answer to signify values that cannot be represented in regular arithmetic.
Also what we colloquially call "wrap around" is in fact just the arithmetic modulo nature of the unsigned integers. I will however use "wrap around" also because it is easier to understand.
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
|
show 13 more comments
Well, I guess this is an exception to "two wrongs don't make a right" :)
What is happening is that there are actually two wrap arounds (unsigned overflows) under the hood and the final result is ends up being mathematically correct.
First,
i
is converted to unsigned and as per wrap around behavior the value isstd::numeric_limits<unsigned>::max() - 9
.When this value is summed with
u
the mathematical result would bestd::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33
which is an overflow and we get another wrap around. So the final result is32
.
As a general rule in an arithmetic expression if you only have unsigned overflows (no matter how many) and if the final mathematical result is representable in the expression data type, then the value of the expression will be the mathematically correct one. This is a consequence of the fact that unsigned integers in C++ obey the laws of arithmetic modulo 2n (see bellow).
Important notice. According to C++ unsigned arithmetic does not overflow:
§6.9.1 Fundamental types [basic.fundamental]
- Unsigned integers shall obey the laws of arithmetic modulo 2n where n
is the number of bits in the value representation of that particular
size of integer 49
49) 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.
I will however leave "overflow" in my answer to signify values that cannot be represented in regular arithmetic.
Also what we colloquially call "wrap around" is in fact just the arithmetic modulo nature of the unsigned integers. I will however use "wrap around" also because it is easier to understand.
Well, I guess this is an exception to "two wrongs don't make a right" :)
What is happening is that there are actually two wrap arounds (unsigned overflows) under the hood and the final result is ends up being mathematically correct.
First,
i
is converted to unsigned and as per wrap around behavior the value isstd::numeric_limits<unsigned>::max() - 9
.When this value is summed with
u
the mathematical result would bestd::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33
which is an overflow and we get another wrap around. So the final result is32
.
As a general rule in an arithmetic expression if you only have unsigned overflows (no matter how many) and if the final mathematical result is representable in the expression data type, then the value of the expression will be the mathematically correct one. This is a consequence of the fact that unsigned integers in C++ obey the laws of arithmetic modulo 2n (see bellow).
Important notice. According to C++ unsigned arithmetic does not overflow:
§6.9.1 Fundamental types [basic.fundamental]
- Unsigned integers shall obey the laws of arithmetic modulo 2n where n
is the number of bits in the value representation of that particular
size of integer 49
49) 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.
I will however leave "overflow" in my answer to signify values that cannot be represented in regular arithmetic.
Also what we colloquially call "wrap around" is in fact just the arithmetic modulo nature of the unsigned integers. I will however use "wrap around" also because it is easier to understand.
edited 2 days ago
answered Jan 14 at 22:36
bolovbolov
31k669130
31k669130
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
|
show 13 more comments
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
3
3
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
@BaummitAugen what? of course it overflows. Add two large unsigned ints, you can't represent a number that doesn't fit in the number format
– Garr Godfrey
Jan 14 at 22:51
1
1
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
@BaummitAugen I went to the standard to prove my point. Turns out I was wrong. Thank you.
– bolov
Jan 14 at 23:00
2
2
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
@GarrGodfrey I searched the standard and he is indeed correct. There is no overflow. And this is because unsigned integers do not represent natural numbers, but, as BaummitAugen said, they represent equivalence classes.
– bolov
Jan 14 at 23:10
2
2
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
@curiousguy I've heard some ppl (experts) saying that having wraparound behavior for unsigned was a bad decision in hindsight. They main reason however was the optimization it inhibits. They argued for regular unsigned to have undefined behavior on overflow and to exist some other data type that had wraparound behavior. But it is what it is.
– bolov
Jan 15 at 2:07
2
2
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
@curiousguy "then why would anyone use them to represent a number of bytes, a number of objects in a container, etc.?" Several prominent members of a committee consider exactly that a historical mistake. channel9.msdn.com/Events/GoingNative/2013/… 9:50, 42:40, 1:02:50
– Baum mit Augen
2 days ago
|
show 13 more comments
i
is in fact promoted to unsigned int
.
Unsigned integers in C and C++ implement arithmetic in ℤ / 2nℤ, where n is the number of bits in the unsigned integer type. Thus we get
[42] + [-10] ≡ [42] + [2n - 10] ≡ [2n + 32] ≡ [32],
with [x] denoting the equivalence class of x in ℤ / 2nℤ.
Of course, the intermediate step of picking only non-negative representatives of each equivalence class, while it formally occurs, is not necessary to explain the result; the immediate
[42] + [-10] ≡ [32]
would also be correct.
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
@JAD Quotient ring.
– user202729
2 days ago
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
|
show 2 more comments
i
is in fact promoted to unsigned int
.
Unsigned integers in C and C++ implement arithmetic in ℤ / 2nℤ, where n is the number of bits in the unsigned integer type. Thus we get
[42] + [-10] ≡ [42] + [2n - 10] ≡ [2n + 32] ≡ [32],
with [x] denoting the equivalence class of x in ℤ / 2nℤ.
Of course, the intermediate step of picking only non-negative representatives of each equivalence class, while it formally occurs, is not necessary to explain the result; the immediate
[42] + [-10] ≡ [32]
would also be correct.
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
@JAD Quotient ring.
– user202729
2 days ago
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
|
show 2 more comments
i
is in fact promoted to unsigned int
.
Unsigned integers in C and C++ implement arithmetic in ℤ / 2nℤ, where n is the number of bits in the unsigned integer type. Thus we get
[42] + [-10] ≡ [42] + [2n - 10] ≡ [2n + 32] ≡ [32],
with [x] denoting the equivalence class of x in ℤ / 2nℤ.
Of course, the intermediate step of picking only non-negative representatives of each equivalence class, while it formally occurs, is not necessary to explain the result; the immediate
[42] + [-10] ≡ [32]
would also be correct.
i
is in fact promoted to unsigned int
.
Unsigned integers in C and C++ implement arithmetic in ℤ / 2nℤ, where n is the number of bits in the unsigned integer type. Thus we get
[42] + [-10] ≡ [42] + [2n - 10] ≡ [2n + 32] ≡ [32],
with [x] denoting the equivalence class of x in ℤ / 2nℤ.
Of course, the intermediate step of picking only non-negative representatives of each equivalence class, while it formally occurs, is not necessary to explain the result; the immediate
[42] + [-10] ≡ [32]
would also be correct.
edited 2 days ago
answered Jan 14 at 22:39
Baum mit AugenBaum mit Augen
40.4k12115147
40.4k12115147
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
@JAD Quotient ring.
– user202729
2 days ago
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
|
show 2 more comments
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
@JAD Quotient ring.
– user202729
2 days ago
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
Shouldn't that be ℤ mod 2n?
– JAD
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
@JAD No. It is correct as it stands.
– Baum mit Augen
2 days ago
1
1
@JAD Quotient ring.
– user202729
2 days ago
@JAD Quotient ring.
– user202729
2 days ago
1
1
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@JAD That should be ℤ / 2ⁿ ℤ
– Eric Duminil
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
@EricDuminil True, thanks.
– Baum mit Augen
2 days ago
|
show 2 more comments
"In the second expression, the int value -42 is converted to unsigned before the addition is done"
yes this is true
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Supposing we are in 32 bits (that change nothing in 64b, this is just to explain) this is computed as 42u + ((unsigned) -10)
so 42u + 4294967286u
and the result is 4294967328u truncated in 32 bits so 32. All was done in unsigned
add a comment |
"In the second expression, the int value -42 is converted to unsigned before the addition is done"
yes this is true
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Supposing we are in 32 bits (that change nothing in 64b, this is just to explain) this is computed as 42u + ((unsigned) -10)
so 42u + 4294967286u
and the result is 4294967328u truncated in 32 bits so 32. All was done in unsigned
add a comment |
"In the second expression, the int value -42 is converted to unsigned before the addition is done"
yes this is true
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Supposing we are in 32 bits (that change nothing in 64b, this is just to explain) this is computed as 42u + ((unsigned) -10)
so 42u + 4294967286u
and the result is 4294967328u truncated in 32 bits so 32. All was done in unsigned
"In the second expression, the int value -42 is converted to unsigned before the addition is done"
yes this is true
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Supposing we are in 32 bits (that change nothing in 64b, this is just to explain) this is computed as 42u + ((unsigned) -10)
so 42u + 4294967286u
and the result is 4294967328u truncated in 32 bits so 32. All was done in unsigned
answered Jan 14 at 22:39
brunobruno
3,4501818
3,4501818
add a comment |
add a comment |
This is part of what is wonderful about 2's complement representation. The processor doesn't know or care if a number is signed or unsigned, the operations are the same. In both cases, the calculation is correct. It's only how the binary number is interpreted after the fact, when printing, that is actually matters (there may be other cases, as with comparison operators)
-10 in 32BIT binary is FFFFFFF6
42 IN 32bit BINARY is 0000002A
Adding them together, it doesn't matter to the processor if they are signed or unsigned, the result is: 100000020. In 32bit, the 1 at the start will be placed in the overflow register, and in c++ is just disappears. You get 0x20 as the result, which is 32.
In the first case, it is basically the same:
-42 in 32BIT binary is FFFFFFD6
10 IN 32bit binary is 0000000A
Add those together and get FFFFFFE0
FFFFFFE0 as a signed int is -32 (decimal). The calculation is correct! But, because it is being PRINTED as an unsigned, it shows up as 4294967264. It's about interpreting the result.
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byteINTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.
– Arne Vogel
2 days ago
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
add a comment |
This is part of what is wonderful about 2's complement representation. The processor doesn't know or care if a number is signed or unsigned, the operations are the same. In both cases, the calculation is correct. It's only how the binary number is interpreted after the fact, when printing, that is actually matters (there may be other cases, as with comparison operators)
-10 in 32BIT binary is FFFFFFF6
42 IN 32bit BINARY is 0000002A
Adding them together, it doesn't matter to the processor if they are signed or unsigned, the result is: 100000020. In 32bit, the 1 at the start will be placed in the overflow register, and in c++ is just disappears. You get 0x20 as the result, which is 32.
In the first case, it is basically the same:
-42 in 32BIT binary is FFFFFFD6
10 IN 32bit binary is 0000000A
Add those together and get FFFFFFE0
FFFFFFE0 as a signed int is -32 (decimal). The calculation is correct! But, because it is being PRINTED as an unsigned, it shows up as 4294967264. It's about interpreting the result.
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byteINTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.
– Arne Vogel
2 days ago
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
add a comment |
This is part of what is wonderful about 2's complement representation. The processor doesn't know or care if a number is signed or unsigned, the operations are the same. In both cases, the calculation is correct. It's only how the binary number is interpreted after the fact, when printing, that is actually matters (there may be other cases, as with comparison operators)
-10 in 32BIT binary is FFFFFFF6
42 IN 32bit BINARY is 0000002A
Adding them together, it doesn't matter to the processor if they are signed or unsigned, the result is: 100000020. In 32bit, the 1 at the start will be placed in the overflow register, and in c++ is just disappears. You get 0x20 as the result, which is 32.
In the first case, it is basically the same:
-42 in 32BIT binary is FFFFFFD6
10 IN 32bit binary is 0000000A
Add those together and get FFFFFFE0
FFFFFFE0 as a signed int is -32 (decimal). The calculation is correct! But, because it is being PRINTED as an unsigned, it shows up as 4294967264. It's about interpreting the result.
This is part of what is wonderful about 2's complement representation. The processor doesn't know or care if a number is signed or unsigned, the operations are the same. In both cases, the calculation is correct. It's only how the binary number is interpreted after the fact, when printing, that is actually matters (there may be other cases, as with comparison operators)
-10 in 32BIT binary is FFFFFFF6
42 IN 32bit BINARY is 0000002A
Adding them together, it doesn't matter to the processor if they are signed or unsigned, the result is: 100000020. In 32bit, the 1 at the start will be placed in the overflow register, and in c++ is just disappears. You get 0x20 as the result, which is 32.
In the first case, it is basically the same:
-42 in 32BIT binary is FFFFFFD6
10 IN 32bit binary is 0000000A
Add those together and get FFFFFFE0
FFFFFFE0 as a signed int is -32 (decimal). The calculation is correct! But, because it is being PRINTED as an unsigned, it shows up as 4294967264. It's about interpreting the result.
answered Jan 14 at 22:50
Garr GodfreyGarr Godfrey
4,04711518
4,04711518
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byteINTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.
– Arne Vogel
2 days ago
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
add a comment |
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byteINTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.
– Arne Vogel
2 days ago
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
1
1
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byte
INTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.– Arne Vogel
2 days ago
As a side note, on x86, most arithmetic operations set various bits in the flags register, which can then be used to e.g. perform branching. For example, addition would set CF (carry flag) to signify that unsigned "wrapping" has occurred, and/or OF (overflow flag) to signify that signed overflow has occurred, if you were to consider the operands signed. There was even a 1-byte
INTO
instruction which generated a software interrupt if OF was set, which could help with debugging, but unfortunately was not supported from higher level languages, and is no longer available in 64 bit mode.– Arne Vogel
2 days ago
1
1
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
Technically speaking, nothing mandates 2's-complement representation. It's just that the modular-arithmetic conversion specified by the standard is exactly equivalent to using 2's-complement (as you'll see if you perform the conversion on a sign-magnitude or 1's-complement system, if it's correct).
– Toby Speight
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
implementing an adder in 1's-compliment or sign-magnitude is very complicated vs 2's compliment. Not required, except for sanity.
– Garr Godfrey
2 days ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54190113%2fis-a-negative-integer-summed-with-a-greater-unsigned-integer-promoted-to-unsigne%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
16
As you can see -10 is not converted to unsigned int.
It is.– tkausl
Jan 14 at 22:28
2
Google about binary numbers and the way they are represented, in particular signedness. Then all shall become clear.
– DeiDei
Jan 14 at 22:33
2
What result were you expecting instead of 32?
– Barmar
Jan 15 at 1:18
Possibly related: c++ safeness of code with implicit conversion between signed and unsigned
– francesco
2 days ago
Thank you all guys. You make it clear for me now.
– Alex24
yesterday