Why is the sign different after subtracting unsigned and signed?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
24
down vote

favorite
3












unsigned int t = 10;
int d = 16;
float c = t - d;
int e = t - d;


Why is the value of c positive but e negative?










share|improve this question









New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 2




    Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
    – Davislor
    5 hours ago














up vote
24
down vote

favorite
3












unsigned int t = 10;
int d = 16;
float c = t - d;
int e = t - d;


Why is the value of c positive but e negative?










share|improve this question









New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 2




    Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
    – Davislor
    5 hours ago












up vote
24
down vote

favorite
3









up vote
24
down vote

favorite
3






3





unsigned int t = 10;
int d = 16;
float c = t - d;
int e = t - d;


Why is the value of c positive but e negative?










share|improve this question









New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











unsigned int t = 10;
int d = 16;
float c = t - d;
int e = t - d;


Why is the value of c positive but e negative?







c++ language-lawyer unsigned negative-number






share|improve this question









New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 7 mins ago









Rishav

2,3241230




2,3241230






New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 10 hours ago









Eugene Kolombet

1213




1213




New contributor




Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Eugene Kolombet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 2




    Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
    – Davislor
    5 hours ago












  • 2




    Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
    – Davislor
    5 hours ago







2




2




Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
– Davislor
5 hours ago




Most compilers have an option to warn you if you're implicitly converting a signed value to unsigned or vice versa. On GCC and Clang, this is -Wconversion. Your question is a good example of why it's a good idea to compile with that.
– Davislor
5 hours ago












2 Answers
2






active

oldest

votes

















up vote
41
down vote













Let's start by analysing the result of t - d.



t is an unsigned int while d is an int, so to do arithmetic on them, the value of d is converted to an unsigned int (C++ rules say unsigned gets preference here). So we get 10u - 16u, which (assuming 32-bit int) wraps around to 4294967290u.



This value is then converted to float in the first declaration, and to int in the second one.



Assuming the typical implementation of float (32-bit single-precision IEEE), its highest representable value is roughly 1e38, so 4294967290u is well within that range. There will be rounding errors, but the conversion to float won't overflow.



For int, the situation's different. 4294967290u is too big to fit into an int, so wrap-around happens and we arrive back at the value -6. Note that such wrap-around is not guaranteed by the standard: the resulting value in this case is implementation-defined(1), which means it's up to the compiler what the result value is, but it must be documented.




(1) C++17 (N4659), [conv.integral] 7.8/3:




If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.







share|improve this answer






















  • Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
    – user1810087
    9 hours ago







  • 3




    @user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
    – Angew
    9 hours ago






  • 1




    It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
    – Ruslan
    7 hours ago











  • @Ruslan Very good point, thans. Answer edited.
    – Angew
    6 hours ago

















up vote
12
down vote













First, you have to understand "usual arithmetic conversions" (that link is for C, but the rules are the same in C++). In C++, if you do arithmetic with mixed types (you should avoid that when possible, by the way), there's a set of rules that decides which type the calculation is done in.



In your case, you are subtracting a signed int from an unsigned int. The promotion rules say that the actual calculation is done using unsigned int.



So your calculation is 10 - 16 in unsigned int arithmetic. Unsigned arithmetic is modulo arithmetic, meaning that it wraps around. So, assuming your typical 32-bit int, the result of this calculation is 2^32 - 6.



This is the same for both lines. Note that the subtraction is completely independent from the assignment; the type on the left side has absolutely no influence on how the calculation happens. It is a common beginner mistake to think that the type on the left side somehow influences the calculation; but float f = 5 / 6 is zero, because the division still uses integer arithmetic.



The difference, then, is what happens during the assignment. The result of the subtraction is implicitly converted to float in one case, and int in the other.



The conversion to float tries to find the closest value to the actual one that the type can represent. This will be some very large value; not quite the one the original subtraction yielded though.



The conversion to int says that if the value fits into the range of int, the value will be unchanged. But 2^32 - 6 is far larger than the 2^31 - 1 that a 32-bit int can hold, so you get the other part of the conversion rule, which says that the resulting value is implementation-defined. This is a term in the standard that means "different compilers can do different things, but they have to document what they do".



For all practical purposes, all compilers that you'll likely encounter say that the bit pattern stays the same and is just interpreted as signed. Because of the way 2's complement arithmetic works (the way that almost all computers represent negative numbers), the result is the -6 you would expect from the calculation.



But all this is a very long way of repeating the first point, which is "don't do mixed type arithmetic". Cast the types first, explicitly, to types that you know will do the right thing.






share|improve this answer






















  • I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
    – Damien_The_Unbeliever
    7 hours ago











  • @Damien_The_Unbeliever Fixed, thanks.
    – Sebastian Redl
    4 hours ago










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',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);






Eugene Kolombet is a new contributor. Be nice, and check out our Code of Conduct.









 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52754505%2fwhy-is-the-sign-different-after-subtracting-unsigned-and-signed%23new-answer', 'question_page');

);

Post as a guest






























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
41
down vote













Let's start by analysing the result of t - d.



t is an unsigned int while d is an int, so to do arithmetic on them, the value of d is converted to an unsigned int (C++ rules say unsigned gets preference here). So we get 10u - 16u, which (assuming 32-bit int) wraps around to 4294967290u.



This value is then converted to float in the first declaration, and to int in the second one.



Assuming the typical implementation of float (32-bit single-precision IEEE), its highest representable value is roughly 1e38, so 4294967290u is well within that range. There will be rounding errors, but the conversion to float won't overflow.



For int, the situation's different. 4294967290u is too big to fit into an int, so wrap-around happens and we arrive back at the value -6. Note that such wrap-around is not guaranteed by the standard: the resulting value in this case is implementation-defined(1), which means it's up to the compiler what the result value is, but it must be documented.




(1) C++17 (N4659), [conv.integral] 7.8/3:




If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.







share|improve this answer






















  • Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
    – user1810087
    9 hours ago







  • 3




    @user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
    – Angew
    9 hours ago






  • 1




    It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
    – Ruslan
    7 hours ago











  • @Ruslan Very good point, thans. Answer edited.
    – Angew
    6 hours ago














up vote
41
down vote













Let's start by analysing the result of t - d.



t is an unsigned int while d is an int, so to do arithmetic on them, the value of d is converted to an unsigned int (C++ rules say unsigned gets preference here). So we get 10u - 16u, which (assuming 32-bit int) wraps around to 4294967290u.



This value is then converted to float in the first declaration, and to int in the second one.



Assuming the typical implementation of float (32-bit single-precision IEEE), its highest representable value is roughly 1e38, so 4294967290u is well within that range. There will be rounding errors, but the conversion to float won't overflow.



For int, the situation's different. 4294967290u is too big to fit into an int, so wrap-around happens and we arrive back at the value -6. Note that such wrap-around is not guaranteed by the standard: the resulting value in this case is implementation-defined(1), which means it's up to the compiler what the result value is, but it must be documented.




(1) C++17 (N4659), [conv.integral] 7.8/3:




If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.







share|improve this answer






















  • Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
    – user1810087
    9 hours ago







  • 3




    @user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
    – Angew
    9 hours ago






  • 1




    It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
    – Ruslan
    7 hours ago











  • @Ruslan Very good point, thans. Answer edited.
    – Angew
    6 hours ago












up vote
41
down vote










up vote
41
down vote









Let's start by analysing the result of t - d.



t is an unsigned int while d is an int, so to do arithmetic on them, the value of d is converted to an unsigned int (C++ rules say unsigned gets preference here). So we get 10u - 16u, which (assuming 32-bit int) wraps around to 4294967290u.



This value is then converted to float in the first declaration, and to int in the second one.



Assuming the typical implementation of float (32-bit single-precision IEEE), its highest representable value is roughly 1e38, so 4294967290u is well within that range. There will be rounding errors, but the conversion to float won't overflow.



For int, the situation's different. 4294967290u is too big to fit into an int, so wrap-around happens and we arrive back at the value -6. Note that such wrap-around is not guaranteed by the standard: the resulting value in this case is implementation-defined(1), which means it's up to the compiler what the result value is, but it must be documented.




(1) C++17 (N4659), [conv.integral] 7.8/3:




If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.







share|improve this answer














Let's start by analysing the result of t - d.



t is an unsigned int while d is an int, so to do arithmetic on them, the value of d is converted to an unsigned int (C++ rules say unsigned gets preference here). So we get 10u - 16u, which (assuming 32-bit int) wraps around to 4294967290u.



This value is then converted to float in the first declaration, and to int in the second one.



Assuming the typical implementation of float (32-bit single-precision IEEE), its highest representable value is roughly 1e38, so 4294967290u is well within that range. There will be rounding errors, but the conversion to float won't overflow.



For int, the situation's different. 4294967290u is too big to fit into an int, so wrap-around happens and we arrive back at the value -6. Note that such wrap-around is not guaranteed by the standard: the resulting value in this case is implementation-defined(1), which means it's up to the compiler what the result value is, but it must be documented.




(1) C++17 (N4659), [conv.integral] 7.8/3:




If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.








share|improve this answer














share|improve this answer



share|improve this answer








edited 40 mins ago









user2357112

143k12147228




143k12147228










answered 9 hours ago









Angew

128k11238334




128k11238334











  • Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
    – user1810087
    9 hours ago







  • 3




    @user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
    – Angew
    9 hours ago






  • 1




    It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
    – Ruslan
    7 hours ago











  • @Ruslan Very good point, thans. Answer edited.
    – Angew
    6 hours ago
















  • Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
    – user1810087
    9 hours ago







  • 3




    @user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
    – Angew
    9 hours ago






  • 1




    It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
    – Ruslan
    7 hours ago











  • @Ruslan Very good point, thans. Answer edited.
    – Angew
    6 hours ago















Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
– user1810087
9 hours ago





Just curious, but does in this case implementation-defined means hardware related? Since, most common hardware is two's-complement, you got this behavior, but it would change on a ones-complement CPU even using the same compiler?
– user1810087
9 hours ago





3




3




@user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
– Angew
9 hours ago




@user1810087 It means that the compiler must document what will happen, which means the compiler authors must think about what will happen, and implement it consistently (or at least document it consistently with implementation). It's quite likely their decision will be influenced by the target HW, and so the documentation of this will be platform-specific.
– Angew
9 hours ago




1




1




It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
– Ruslan
7 hours ago





It's not behavior which is implementation-defined — only value (see your own footnote). In particular, implementation can't throw an exception, raise a signal etc. due to such conversion.
– Ruslan
7 hours ago













@Ruslan Very good point, thans. Answer edited.
– Angew
6 hours ago




@Ruslan Very good point, thans. Answer edited.
– Angew
6 hours ago












up vote
12
down vote













First, you have to understand "usual arithmetic conversions" (that link is for C, but the rules are the same in C++). In C++, if you do arithmetic with mixed types (you should avoid that when possible, by the way), there's a set of rules that decides which type the calculation is done in.



In your case, you are subtracting a signed int from an unsigned int. The promotion rules say that the actual calculation is done using unsigned int.



So your calculation is 10 - 16 in unsigned int arithmetic. Unsigned arithmetic is modulo arithmetic, meaning that it wraps around. So, assuming your typical 32-bit int, the result of this calculation is 2^32 - 6.



This is the same for both lines. Note that the subtraction is completely independent from the assignment; the type on the left side has absolutely no influence on how the calculation happens. It is a common beginner mistake to think that the type on the left side somehow influences the calculation; but float f = 5 / 6 is zero, because the division still uses integer arithmetic.



The difference, then, is what happens during the assignment. The result of the subtraction is implicitly converted to float in one case, and int in the other.



The conversion to float tries to find the closest value to the actual one that the type can represent. This will be some very large value; not quite the one the original subtraction yielded though.



The conversion to int says that if the value fits into the range of int, the value will be unchanged. But 2^32 - 6 is far larger than the 2^31 - 1 that a 32-bit int can hold, so you get the other part of the conversion rule, which says that the resulting value is implementation-defined. This is a term in the standard that means "different compilers can do different things, but they have to document what they do".



For all practical purposes, all compilers that you'll likely encounter say that the bit pattern stays the same and is just interpreted as signed. Because of the way 2's complement arithmetic works (the way that almost all computers represent negative numbers), the result is the -6 you would expect from the calculation.



But all this is a very long way of repeating the first point, which is "don't do mixed type arithmetic". Cast the types first, explicitly, to types that you know will do the right thing.






share|improve this answer






















  • I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
    – Damien_The_Unbeliever
    7 hours ago











  • @Damien_The_Unbeliever Fixed, thanks.
    – Sebastian Redl
    4 hours ago














up vote
12
down vote













First, you have to understand "usual arithmetic conversions" (that link is for C, but the rules are the same in C++). In C++, if you do arithmetic with mixed types (you should avoid that when possible, by the way), there's a set of rules that decides which type the calculation is done in.



In your case, you are subtracting a signed int from an unsigned int. The promotion rules say that the actual calculation is done using unsigned int.



So your calculation is 10 - 16 in unsigned int arithmetic. Unsigned arithmetic is modulo arithmetic, meaning that it wraps around. So, assuming your typical 32-bit int, the result of this calculation is 2^32 - 6.



This is the same for both lines. Note that the subtraction is completely independent from the assignment; the type on the left side has absolutely no influence on how the calculation happens. It is a common beginner mistake to think that the type on the left side somehow influences the calculation; but float f = 5 / 6 is zero, because the division still uses integer arithmetic.



The difference, then, is what happens during the assignment. The result of the subtraction is implicitly converted to float in one case, and int in the other.



The conversion to float tries to find the closest value to the actual one that the type can represent. This will be some very large value; not quite the one the original subtraction yielded though.



The conversion to int says that if the value fits into the range of int, the value will be unchanged. But 2^32 - 6 is far larger than the 2^31 - 1 that a 32-bit int can hold, so you get the other part of the conversion rule, which says that the resulting value is implementation-defined. This is a term in the standard that means "different compilers can do different things, but they have to document what they do".



For all practical purposes, all compilers that you'll likely encounter say that the bit pattern stays the same and is just interpreted as signed. Because of the way 2's complement arithmetic works (the way that almost all computers represent negative numbers), the result is the -6 you would expect from the calculation.



But all this is a very long way of repeating the first point, which is "don't do mixed type arithmetic". Cast the types first, explicitly, to types that you know will do the right thing.






share|improve this answer






















  • I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
    – Damien_The_Unbeliever
    7 hours ago











  • @Damien_The_Unbeliever Fixed, thanks.
    – Sebastian Redl
    4 hours ago












up vote
12
down vote










up vote
12
down vote









First, you have to understand "usual arithmetic conversions" (that link is for C, but the rules are the same in C++). In C++, if you do arithmetic with mixed types (you should avoid that when possible, by the way), there's a set of rules that decides which type the calculation is done in.



In your case, you are subtracting a signed int from an unsigned int. The promotion rules say that the actual calculation is done using unsigned int.



So your calculation is 10 - 16 in unsigned int arithmetic. Unsigned arithmetic is modulo arithmetic, meaning that it wraps around. So, assuming your typical 32-bit int, the result of this calculation is 2^32 - 6.



This is the same for both lines. Note that the subtraction is completely independent from the assignment; the type on the left side has absolutely no influence on how the calculation happens. It is a common beginner mistake to think that the type on the left side somehow influences the calculation; but float f = 5 / 6 is zero, because the division still uses integer arithmetic.



The difference, then, is what happens during the assignment. The result of the subtraction is implicitly converted to float in one case, and int in the other.



The conversion to float tries to find the closest value to the actual one that the type can represent. This will be some very large value; not quite the one the original subtraction yielded though.



The conversion to int says that if the value fits into the range of int, the value will be unchanged. But 2^32 - 6 is far larger than the 2^31 - 1 that a 32-bit int can hold, so you get the other part of the conversion rule, which says that the resulting value is implementation-defined. This is a term in the standard that means "different compilers can do different things, but they have to document what they do".



For all practical purposes, all compilers that you'll likely encounter say that the bit pattern stays the same and is just interpreted as signed. Because of the way 2's complement arithmetic works (the way that almost all computers represent negative numbers), the result is the -6 you would expect from the calculation.



But all this is a very long way of repeating the first point, which is "don't do mixed type arithmetic". Cast the types first, explicitly, to types that you know will do the right thing.






share|improve this answer














First, you have to understand "usual arithmetic conversions" (that link is for C, but the rules are the same in C++). In C++, if you do arithmetic with mixed types (you should avoid that when possible, by the way), there's a set of rules that decides which type the calculation is done in.



In your case, you are subtracting a signed int from an unsigned int. The promotion rules say that the actual calculation is done using unsigned int.



So your calculation is 10 - 16 in unsigned int arithmetic. Unsigned arithmetic is modulo arithmetic, meaning that it wraps around. So, assuming your typical 32-bit int, the result of this calculation is 2^32 - 6.



This is the same for both lines. Note that the subtraction is completely independent from the assignment; the type on the left side has absolutely no influence on how the calculation happens. It is a common beginner mistake to think that the type on the left side somehow influences the calculation; but float f = 5 / 6 is zero, because the division still uses integer arithmetic.



The difference, then, is what happens during the assignment. The result of the subtraction is implicitly converted to float in one case, and int in the other.



The conversion to float tries to find the closest value to the actual one that the type can represent. This will be some very large value; not quite the one the original subtraction yielded though.



The conversion to int says that if the value fits into the range of int, the value will be unchanged. But 2^32 - 6 is far larger than the 2^31 - 1 that a 32-bit int can hold, so you get the other part of the conversion rule, which says that the resulting value is implementation-defined. This is a term in the standard that means "different compilers can do different things, but they have to document what they do".



For all practical purposes, all compilers that you'll likely encounter say that the bit pattern stays the same and is just interpreted as signed. Because of the way 2's complement arithmetic works (the way that almost all computers represent negative numbers), the result is the -6 you would expect from the calculation.



But all this is a very long way of repeating the first point, which is "don't do mixed type arithmetic". Cast the types first, explicitly, to types that you know will do the right thing.







share|improve this answer














share|improve this answer



share|improve this answer








edited 4 hours ago

























answered 9 hours ago









Sebastian Redl

48.3k474110




48.3k474110











  • I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
    – Damien_The_Unbeliever
    7 hours ago











  • @Damien_The_Unbeliever Fixed, thanks.
    – Sebastian Redl
    4 hours ago
















  • I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
    – Damien_The_Unbeliever
    7 hours ago











  • @Damien_The_Unbeliever Fixed, thanks.
    – Sebastian Redl
    4 hours ago















I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
– Damien_The_Unbeliever
7 hours ago





I think you meant 2^31-1 for your second value in paragraph 7. Because "2^32 - 6 is far larger than the 2^32 - 1" doesn't, on the face of it, seem an obvious thing to assert. Most people would think that the first was exactly 5 less than the second, not far larger :-)
– Damien_The_Unbeliever
7 hours ago













@Damien_The_Unbeliever Fixed, thanks.
– Sebastian Redl
4 hours ago




@Damien_The_Unbeliever Fixed, thanks.
– Sebastian Redl
4 hours ago










Eugene Kolombet is a new contributor. Be nice, and check out our Code of Conduct.









 

draft saved


draft discarded


















Eugene Kolombet is a new contributor. Be nice, and check out our Code of Conduct.












Eugene Kolombet is a new contributor. Be nice, and check out our Code of Conduct.











Eugene Kolombet is a new contributor. Be nice, and check out our Code of Conduct.













 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52754505%2fwhy-is-the-sign-different-after-subtracting-unsigned-and-signed%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

Long meetings (6-7 hours a day): Being “babysat” by supervisor

Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

Confectionery