How does C convert signed hex number to negative numbers? - c

So recently, I met this problem:
Given: int x; unsigned int y; x = 0xAB78; y = 0xAB78; write a program to display the decimal values of x and y on the screen.
And here is the program I wrote: ( I am on a 64-bit windows 7 machine)
#include<stdio.h>
#include<math.h>
int main()
{
short int x;
unsigned short int y;
x = 0xAB78;
y = 0xAB78;
printf("The decimal values of x and y are: %d & %hu.\n", x, y);
return 0;
}
The output I got is:
x=-21640, and y=43896.
I am ok with the unsigned hex number,
since 0xAB78 = 10*16^3 + 11*16^2 + 7*16^1 + 8*16^0 = 43896.
However for the signed hex number,
should it be: -1*16^3 + 11*16^2 + 7*16^1 +8*16^0 = -1160?
why is it -21640 then?
Thank you for your time!

signed short int range values is [-32768 ; 32767]. Value 0xAB78 (or 43896) won't fit into, so it overflows into -32768 + (43896 - 32768) thus ending in -21640.

If the constant does not fit in your signed integer type, the result is implementation-defined.
C allows 1s-complement, sign-and-magnitude and 2s-complement for signed numbers. Also, short has minimum width 16 value-bits and may contain non-value bits. Trap-representations are also possible.
That gives quite a lot of possible results.
For POSIX and Windows machines, 16-bit 2s complement is mandatory, thus just reduce the constant modulo 2**16. If that is >= 2**15, subtract 2**16.

Related

Why is `x - y <= x` true, when x=0x80000000, y = 1(32-bit complement)? [duplicate]

This question already has answers here:
Detecting signed overflow in C/C++
(13 answers)
Closed 1 year ago.
I want to know if x - y overflows.
Below is my code.
#include <stdio.h>
/* Determine whether arguments can be subtracted without overflow */
int tsub_ok(int x, int y)
{
return (y <= 0 && x - y >= x) || (y >= 0 && x - y <= x);
}
int main()
{
printf("0x80000000 - 1 : %d\n", tsub_ok(0x80000000, 1));
}
Why can't I get the result I expect?
You can't check for overflow of signed integers by performing the offending operation and seeing if the result wraps around.
First, the value 0x80000000 passed to the function is outside the range of a 32 bit int. So it undergoes an implementation defined conversion. On most systems that use 2's compliment, this will result in the value with that representation which is -2147483648 which also happens to be the value of INT_MIN.
Then you attempt to execute x - y which results in signed integer overflow which triggers undefined behavior, giving you an unexpected result.
The proper way to handle this is to perform some algebra to ensure the overflow does not happen.
If x and y have the same sign then subtracting won't overflow.
If the signs differ and x is positive, one might naively try this:
INT_MAX >= x - y
But this could overflow. Instead change it to the mathematically equivalent:
INT_MAX + y >= x
Because y is negative, INT_MAX + y doesn't overflow.
A similar check can be done when x is negative with INT_MIN. The full check:
if (x>=0 && y>=0) {
return 1;
} else if (x<=0 && y<=0) {
return 1;
} else if (x>=0 && INT_MAX + y >= x) {
return 1;
} else if (x<0 && INT_MIN + y <= x) {
return 1;
} else {
return 0;
}
Yes, x - y overflows.
We assume int and unsigned int are 32 bits in the C implementation you are using, as indicated in the title, and that two’s complement is used for int. Then the range of values for int is −231 to +231−1.
In tsub_ok(0x80000000, 1), the constant 0x80000000 has the value 231, and its type is unsigned int since it will not fit in an int. Then this value is passed to tsub_ok. Since the first parameter of tsub_ok has type int, the value is converted to int.
By C 2018 6.3.1.3 3, the conversion is implementation-defined. Many C implementations “wrap” the value modulo 232. Assuming your C implementation does this, the result of converting 231 to int is −231.
Then, inside the function, x - y is −231 − 1, and the result of that overflows the int type. The C standard does not define the behavior of the program when signed integer overflow occurs, and so any test that relies on comparing x - y when it may overflow is not supported by the C standard.
Here an int is 32 bits. This means it has a total range of 2^32 possible values. Converting this to hex, that's a max of 0xFFFFFFFF(when unsigned), but not signed. A signed int will have a max hex value of 0x7FFFFFFF. Thus, you cannot store 0x80000000 in an int here and have everything work.
In computer programming, signed and unsigned numbers are represented only as sequences of bits. Bit 31 is the sign bit for a 32-bit signed int, hence the highest 32-bit int you can store is 0x7FFFFFFF, hence the overflow with 0x80000000 as signed int.
Remember, a signed int is an integer that can be both positive and negative. This is as opposed to an unsigned int, which can only be used to hold a positive integer.
What you are trying to do is, you are trying a signed int variable hold an unsigned value - which causes the overflow.
For more info check Signed number representations or refer any beginner level digital number systems and programming book.

Error on casting unsigned int to float

For the following program.
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
It is very strange that output is
d = 4294965248.000000
When I change the magic number 3 in the expression to calculate d to 3.0, I got correct result:
d = 2000.000000
If I change the type of a, b, c to int, I also got correct result.
I guess this error occurred by the conversion from unsigned int to float, but I do not know details about how the strange result was created.
I think you realize that you casting minus to unsigned int before assignment to float. If you run the below code, you will get highly likely 4294965296
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
printf("%u", -((a*b)*(c/3)));
return 0;
}
The -2000 to the right of your equals sign is set up as a signed
integer (probably 32 bits in size) and will have the hexadecimal value
0xFFFFF830. The compiler generates code to move this signed integer
into your unsigned integer x which is also a 32 bit entity. The
compiler assumes you only have a positive value to the right of the
equals sign so it simply moves all 32 bits into x. x now has the
value 0xFFFFF830 which is 4294965296 if interpreted as a positive
number. But the printf format of %d says the 32 bits are to be
interpreted as a signed integer so you get -2000. If you had used
%u it would have printed as 4294965296.
#include <stdio.h>
#include <limits.h>
int main()
{
float d = 4294965296;
printf("d = %f\n\n", d);
return 0;
}
When you convert 4294965296 to float, the number you are using is long to fit into the fraction part. Now that some precision was lost. Because of the loss, you got 4294965248.000000 as I got.
The IEEE-754 floating-point standard is a standard for representing
and manipulating floating-point quantities that is followed by all
modern computer systems.
bit 31 30 23 22 0
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
The bit numbers are counting from the least-significant bit. The first
bit is the sign (0 for positive, 1 for negative). The following
8 bits are the exponent in excess-127 binary notation; this
means that the binary pattern 01111111 = 127 represents an exponent
of 0, 1000000 = 128, represents 1, 01111110 = 126 represents
-1, and so forth. The mantissa fits in the remaining 24 bits, with
its leading 1 stripped off as described above. Source
As you can see, when doing conversion 4294965296 to float, precision which is 00011000 loss occurs.
11111111111111111111100 00011000 0 <-- 4294965296
11111111111111111111100 00000000 0 <-- 4294965248
This is because you use - on an unsigned int. The - inverts the bits of the number. Lets print some unsigned integers:
printf("Positive: %u\n", 2000);
printf("Negative: %u\n", -2000);
// Output:
// Positive: 2000
// Negative: 4294965296
Lets print the hex values:
printf("Positive: %x\n", 2000);
printf("Negative: %x\n", -2000);
// Output
// Positive: 7d0
// Negative: fffff830
As you can see, the bits are inverted. So the problem comes from using - on unsigned int, not from casting unsigned intto float.
As others have said, the issue is that you are trying to negate an unsigned number. Most of the solutions already given have you do some form of casting to float such that the arithmetic is done on floating point types. An alternate solution would be to cast the results of your arithmetic to int and then negate, that way the arithmetic operations will be done on integral types, which may or may not be preferable, depending on your actual use-case:
#include <stdio.h>
int main(void)
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -(int)((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
Your whole calculation will be done unsigned so it is the same as
float d = -(2000u);
-2000 in unsigned int (assuming 32bits int) is 4294965295
this gets written in your float d. But as float can not save this exact number it gets saved as 4294965248.
As a rule of thumb you can say that float has a precision of 7 significant base 10 digits.
What is calculated is 2^32 - 2000 and then floating point precision does the rest.
If you instead use 3.0 this changes the types in your calculation as follows
float d = -((a*b)*(c/3.0));
float d = -((unsigned*unsigned)*(unsigned/double));
float d = -((unsigned)*(double));
float d = -(double);
leaving you with the correct negative value.
you need to cast the ints to floats
float d = -((a*b)*(c/3));
to
float d = -(((float)a*(float)b)*((float)c/3.0));
-((a*b)*(c/3)); is all performed in unsigned integer arithmetic, including the unary negation. Unary negation is well-defined for an unsigned type: mathematically the result is modulo 2N where N is the number of bits in unsigned int. When you assign that large number to the float, you encounter some loss of precision; the result, due to its binary magnitude, is the nearest number to the unsigned int that divides 2048.
If you change 3 to 3.0, then c / 3.0 is a double type, and the result of a * b is therefore converted to a double before being multiplied. This double is then assigned to a float, with the precision loss already observed.

Depiction of binary digit changes during promotion from signed to unsigned integers/what happens?

y is promoted to unsigned int and compared with x here.Does binary number comparison happen everytime? Then if(12 == -4) is done, why can't it promote LHS to unsigned and print "same"?(considering 12 = 1100, -4 = 1100)Please correct if I am wrong.
#include<stdio.h>
int main()
{
unsigned int x = -1;
int y = ~0;
if(x == y)//1.what happens if( y == x) is given?.O/P is "same" then also.
printf("same");//output is "same"
else
printf("not same");
printf("%d",x);//2.output is -1.Won't x lose it's sign when unsigned is given?My hunch is x should become +1 here.
getchar();
return 0;
}
Please also provide the binary number working for the above code and answers to 1. and 2. in the code comments.Thank you.
First check in your system for size of unsigned int.
in my machine: printf("%zu\n",sizeof(unsigned int));//4 byte
as we have 4 bytes to store an Uint data type, we can say
unsigned int x ;//
x:Range[0, Max_number_with_4byte]
Max_number_with_4byte: (2^32) - 1 = 0xFFFFFFFF
obviously x can hold only positive numbers because of unsigned.
but you give to x = -1;, suppose a circular behaviour, when we put back one step from 0, x reach to last point: Max_number_with_4byte.
and printing x to screen shows: 0xFFFFFFFF
see hex equivalent of x with printf("%x\n",(unsigned int )x);
and printf("%y\n",(unsigned int )y); to see equality of x,y.
consider y = ~0; we have 32 bits for y if ~ operator use in y all bits are changes to 1, in hex form we see FFFFFFFF. (we cant print binary numbers with printf and use equal hex representation)
you can see this online calculator how to convert -1 to 0xFFFFFFFF
Answer to your Question
y is not promoted to unsigned int. it is just changes its bits form 0 -> 1
Does binary number comparison happen every time?
Yes in every conditions for example in if(10 > 20) first both 10 and 20 converted to its correspondent binary numbers then compare.
if (12 == -4) see my above explanation.
-4 not equals to 1100 inside computer (your variable).
-4 = 0xFFFFFFFC see
An unsigned int =-1 should actually interpreted as the max unsigned int(4294967295); surely is not transformed into 1.

summing unsigned and signed ints, same or different answer?

If I have the following code in C
int main()
{
int x = <a number>
int y = <a number>
unsigned int v = x;
unsigned int w = y;
int ssum = x * y;
unsigned int usum = v * w;
printf("%d\n", ssum);
printf("%d\n", usum);
if(ssum == usum){
printf("Same\n");
} else {
printf("Different\n");
}
return 0;
}
Which would print the most? Would it be equal since signed and unsigned would produce the same result, then if you have a negative like -1, when it gets assigned to int x it becomes 0xFF, and if you want to do -1 + (-1), if you do it the signed way to get -2 = 0xFE, and since the unsigned variables would be set to 0xFF, if you add them you would still get 0xFE. And the same holds true for 2 + (-3) or -2 + 3, in the end the hexadecimal values are identical. So in C is that what's looked at when it sees signedSum == unsignedSum? It doesnt care that one is actually a large number and the other is -2, as long at the 1's and 0's are the same?
Are there any values that would make this not true?
The examples you have given are incorrect in C. Also, converting between signed and unsigned types is not required to preserve bit patterns (the conversion is by value), although with some representations bit patterns are preserved.
There are circumstances where the result of operations will be the same, and circumstances where the result will differ.
If the (actual) sum of adding two ints would overflow an int
(i.e. value outside range that an int can represent) the result is
undefined behaviour. Anything can happen at that point (including
the program terminating abnormally) - subsequently converting to an unsigned doesn't change anything.
Converting an int with negative value to unsigned int uses modulo
arithmetic (modulo the maximum value that an unsigned can
represent, plus one). That is well defined by the standard, but
means -1 (type int) will convert to the maximum value that an
unsigned can represent (i.e. UINT_MAX, an implementation defined
value specified in <limits.h>).
Similarly, adding two variables of type unsigned int always uses
modulo arithmetic.
Because of things like this, your question "which would produce the most?" is meaningless.

Unsigned and signed division in C

In my program two variables are declared as signed long (let say X and Y on 32 bit machine) and these divided one by other(X/Y).
The final value is assigned to a unsigned long variable(Let say Z). I am not sure whether this is right or wrong assignment. I am just debugging a code that was written by some one. I guess this may lead to overflow or undefined state.
What happens in below four scenarios,
Z =+X/+Y
Z =+X/-Y
Z =-X/+Y
Z =-X/-Y
I know that %u for unsigned and %d for integer. My question is regarding what value would be stored in Z in the above four scenarios.
Any help would be greatly appreciated.
If your variables are signed, all is fine. Perhaps there is a (unwanted?) conversion afterwards if you gert a negative division result.
Working with expressions containing unsigned values is more painful, e.g.
(1U-2)/10
gives unexpected results.
Z would store the value of the integer division, but as Z is unsigned, all values will be positive, and thus the sign bit will not be processed as such, but as part of the number, and also there will be no two's complement conversion. For example, if unsigned int is 32-bit wide:
X = 1, Y = 1 -> Z = 1
X = -1, Y = 1 -> Z = 4294967295 = 0xFFFFFFFF (this would be -1 -two's complement- if Z was signed)
You'll get garbage if result of division is negative.
For example:
unsigned z;
int a = 10;
int b = -2;
z = a/b;
then z == 4294967291.

Resources