Range of signed char - c

Why the range of signed character is -128 to 127 but not -127 to 128 ?

That is because of the way two's complement encoding works: 0 is treated as a "positive" number (signed bit off), so, therefore, the number of available positive values is reduced by one.
In ones' complement encoding (which is not very common nowadays, but in the olden days, it was), there were separate values for +0 and -0, and so the range for an 8-bit quantity is -127 to +127.

In 8-bit 2's complement encoding numbers -128 and +128 have the same representation: 10000000. So, the designer of the hardware is presented with an obvious dilemma: how to interpret bit-pattern 10000000. Formally, it will work either way. If they decide to interpret it as +128, the resultant range will be -127..+128. If they decide to interpret it as -128, the resultant range will be -128..+127.
In actual real-life 2's complement representation the latter approach is chosen because it satisfies the following nice convention: all bit-patterns with 1 in higher-order bit represent negative numbers.
It is worth noting though, that language specification does not require 2's-complement implementations to treat the 100...0 bit pattern as a valid value in any signed integer type. E.g. implementations are allowed to restrict 8-bit signed char to -127..+127 range and regard 10000000 as an invalid bit combination (trap representation).

I think an easy way to explain this for the common soul is :
A bit is a value 0 or 1, or 2 possibilities
A 2-bit holds two combinations or 0 and 1 for four possible values : 00, 01, 10, and 11.
A 3-bit holds three combinations for a total of eight possible values : 000 to 111.
Thus n-bits holds n combinations for a total of 2^n possible values. Therefore, an 8-bit value is 2^8 = 256 possible values.
For signed numbers, the most significant bit (the first one reading the value from left to right) is the sign bit; that leaves a possibility of 2^(n-1) possible values. For an 8-bit signed number, this is 2^7 = 128 possible values for each sign. But since the positive sign includes the zero (0 to 127 = 128 different values, and 128 + 128 = 2^8 = 256), the negative sign includes -1 to... -128 for 128 different values also. Where :
10000000 = -128
...
11111111 = -1
00000000 = 0
...
01111111 = 127

#include <limits.h>
#include <stdio.h>
...
printf("range of signed character is %i ... %i", CHAR_MIN, CHAR_MAX );

If you just consider twos complement as arithmetic modulo 256, then the cutoff between positive and negative is purely arbitrary. You could just as well have put it at 63/-192, 254/-1, 130/-125, or anywhere else. However, as a standard signed integer format, twos complement came by convention put put the cutoff at 127/-128. This cutoff has one big benefit: the high bit being set corresponds directly to the number being negative.
As for the C language, it leaves the format of signed numbers up to the implementation, but only offers 3 choices of implementation, all of which use a "sign bit": sign/magnitude, ones complement, and twos complement.

If you look at ranges of chars and ints there seems to be one extra number on the negative side. This is because a negative number is always stored as 2’s compliment of its binary. For example, let us see how -128 is stored. Firstly, binary of 128 is calculated (10000000), then its 1’s compliment is obtained (01111111). A 1’s compliment is obtained by changing all 0s to 1s and 1s to 0s. Finally, 2’s compliment of this number, i.e. 10000000, gets stored. A 2’s compliment is obtained by adding 1 to the 1’s compliment. Thus, for -128, 10000000 gets stored. This is an 8-bit number and it can be easily accommodated in a char. As against this, +128 cannot be stored in a char because its binary 010000000 (left-most 0 is for positive sign) is a 9-bit number. However +127 can be stored as its binary 01111111 turns out to be a 8-bit number.

Step 1:
If you take 2's complement of any number from 0 up to 127 the bit number 8 will always be 1. So lets reserve that info.
Step2 :
if you find the -127 by applying 2's complement into +127 you will find "1 0 0 0 0 0 0 1" and finally if you substract 1 from this number then the smallest 8 bit number -128 will be achieved as "1 0 0 0 0 0 0 0"
As a result if we combine the info that we reserved at step 1 and the result from step2, we come to the conclusion that, the most significiant bit or bit number 8 in char containers must always be 1 so called signed bit.

Related

Finding the difference between a negative and positive binary Number

I know that we can represent binary Numbers in several ways, but I am really not sure how to distinguish a positive binary number from a negative one.
If we have the number +13, then its binary representation looks like this:
1101
and its negative representation looks like this:
11101
What I understand is that if you need to distinguish them, then the presence of 0 is important in number +13:
01101
Even so, I still cannot distinguish between:
11101 ///Here is the representation of -13
and:
11101 ///Here is the representation of +29
I understand that here is used another scheme called "two's complement" which I need to apply it.
How can I distinguish those two binary representations?
As the other guys say the question can I distinguish those two binary representations as no sense. A sequence of bits is neutral, when you transform it in a number you do the transformation for a given representation. It can represent an int, an unsigned int, a float or anything you want. It is like if I ask you what is a coin, this word exists (at least ?) in English and in French with a totally different meaning (the french word coin means corner in English), to answer me you need to choose a language, you cannot answer without.
About the "two's complement", it is the way compatible for the standard representation used in our CPU to change the sign of signed int. The first complement is to replace all 0 by 1 and all 1 by 0, the second complement is to add 1 to the previous result.
Supposing the word has 5 bits, the int value 13 is 01101 in binary. If we want -13 the first complement on 13 gives 10010, adding 1 that gives 10011.
But still having 5 bits words, 10011 for an unsigned int correspond to the value 19.
For an int on 5 bits the lower negative number is by definition 10000, if we try to change its sign : first complement = 01111, adding 1 = 10000 ! In fact there is an overflow, 5 bits are not enough.
The same sequence of bits can have radically different meanings based on context.
Integer types have a fixed number of bits - the C language definition mandates that the signed int type must be able to represent at least the range [-32,767...32,767], meaning an int must be at least 16 bits wide1.
There are several different ways to represent signed integers. The most common is 2's complement, but some architectures may use 1's complement or sign-magnitude.
To flip the sign on a 2's complement number, do a bitwise negation and add 1 (this example assumes 8 bit integers):
00001101 == 13
11110010 + 1 == 11110011 == -13
11110011 == -13
00001100 + 1 == 00001101 == 13
One of the chief advantages of 2's complement is that you have a single representation for 0, and it gives you a slightly wider range of values - [-2n-1..2n-1-1]
To flip the sign on a 1's complement number, you simply do a bitwise negation:
00001101 == 13
11110010 == -13
11110010 == -13
00001101 == 13
With 1's complement, you have positive and negative representations for 0 - 00000000 and 11111111 - and the range is [-2n-1-1..2n-1-1]
With sign-magnitude, you leave the value bits as-is and flip the sign bit:
00001101 == 13
10001101 == -13
Like 1's complement, you get two encodings for positive and negative 0 - 00000000 and 10000000.
Unsigned integer types have the same width as their signed counterparts, and their range is [0..2n-1].
So, the bit sequence 11110011 can mean -13 in 2's complement, -12 in 1's complement, -115 in sign-magnitude, or 243 unsigned.
Note that some architectures may use padding bits, such that it takes more than 16 bits to represent 32,767.
The binary value is open to the encoding.
1101
11012 has the value of 1310 when there is no encoded sign bit.
When a sign-bit is used, the width N is also important.
When N > 4,
using 2's complement, 1s' complement, sign magnitude, the value is still 1310.
11101
If 111012 was saved in unsigned field of size 5 or more, the value is 2910.
If 111012 was saved in a 5-bit signed int field, the value is depends on the int encoding (which is certainly 2's complement).
2's complement: -310
1s' complement: -210
Sign magnitude: -1310 (Apparently OP's initial view)
Let's say you have 5 bit computer. 5 bits divided into 1 sign bit + 4 number bits.
Limits are 2^4-1 to -2^4 i.e. 15 to -16.
13=01101
-13= 10010 : 2's complement representation. It won't be 18 because 18 can't fit in the range.

Why does subtracting a negative 8-bit value from the 9-bit pattern 100000000 give the magnitude?

My textbook provides the following explanation for the two's complement method for signed integers:
We’ll discuss this method as it applies to a 1-byte value. In that
context, the values 0 through 127 are represented by the last 7 bits,
with the high-order bit set to 0. So far, that’s the same as the
sign-magnitude method. Also, if the high-order bit is 1, the value is
negative. The difference comes in determining the value of that
negative number. Subtract the bit-pattern
for a negative number from the 9-bit pattern 100000000 (256 as
expressed in binary), and
the result is the magnitude of the value.
None of this makes any sense to me. Typical processors use octets (8-bit bytes). What does it mean by subtracting the 8-bit byte from the 9-bit byte?
Basically, for efficient computation, you want to have the same operations (addition, subtraction, etc.) to be performed the same way, regardless of the sign. So first, consider the case of unsigned bytes.
With 8 bits, you can represent any value between 0-255. Addition and subtraction work the same way as usual (modulo 256), and everything is fine.
Now, imagine that when you are at 127, incrementing by 1 gives you -128. We're still counting modulo 256, but the top 128 numbers have shifted by 256. Now, let's examine addition:
10 + (-5) = 10 + 251 (unsigned) = 261 = 5 (modulo 255).
Everything works as expected. So, in our new representation, -128 is 127 + 1, which is 01111111 + 1 which is 10000000. -1 will be 11111111. I hope I've helped.
You have 1 byte (8 digit number with each digit being a 0 or a 1)
2's complement works by looking at the first digit
10010011
^ this one
If it's a 0, then the number is positive and you can continue to convert binary to decimal normally.
If it's 1, then it's negative. Convert it normally (bin(10010011) = 147) and THEN subtract 256 (147 - 256 = -109), and there is your 2's complement number.
My memory about two's complement says:
"Flip the bits plus one"
Indeed, the following makes a number negative:
int i, j= 127;
i = (~j)+1;
printf ("%d\n",i); // prints -127

range of size of signed int

i was thinking about size of int(signed and unsigned). The size of unsigned integer is very obvious to calculate but when it came to signed i got confused.. like if int is of 2 bytes and 15th byte is for sign then its size is 32767 thats understandable .. but when i tried to calculate the -ve minimum i did this 1 1111111111111..(16 ones). ignoring the signed bit(16th) the value was still 32767 so i got range +32767 to -32767(and thats not the right range) .
or maybe this is not the right way to calculate the range because compiler will take it as -1.
so how +32767 to -32768 is calculated ??
but when i tried to calculate the -ve minimum i did this 1 1111111111111..(16 ones). ignoring the signed bit(16th) the value was still 32767 so i got range +32767 to -32767(and thats not the right range)
Well, it can be the right range if your architecture defines the negative range the same way you do: that is, if it uses a "sign and magnitude" (or "sign and absolute value") representation.
That's completely valid: in C, signed integers are NOT necessarily represented using 2's complement (as you seem to assume).
If your platform, however, does indeed use 2's complement, then your method for calculating the minimal negative value is incorrect. Then you have to count backwards, from 1111 1111 1111 1111 (which is -1), until 1000 0000 0000 0000, which turns out to be -32768.
This is true because all of the 15 bits are changing (only the 0th bit, the sign bit stays the same as you can see), so there are 2 ^ 15 possible variations, and if you start from -1, you will arrive at -32768.
For twos complement representation, the negation of a number is achieved by taking the complement of the number and then adding 1. So, the number 0xFFFF complemented is 0x0000, and adding 1 yields 0x0001. So in twos complement, -1 is represented by the binary value of all bits set.
The largest positive signed 16 bit number is 0x7FFF, and its negative representation is 0x8001. Looking at that negative number, you can see that by subtracting one more from that value, we get negative number of one larger magnitude: 0x8000.
So, 32767 = 0x7FFF, and -32768 = 0x8000.

What does signed and unsigned values mean?

What does signed mean in C? I have this table to show:
This says signed char 128 to +127. 128 is also a positive integer, so how can this be something like +128 to +127? Or do 128 and +127 have different meanings? I am referring to the book Apress Beginning C.
A signed integer can represent negative numbers; unsigned cannot.
Signed integers have undefined behavior if they overflow, while unsigned integers wrap around using modulo.
Note that that table is incorrect. First off, it's missing the - signs (such as -128 to +127). Second, the standard does not guarantee that those types must fall within those ranges.
By default, numerical values in C are signed, which means they can be both negative and positive. Unsigned values on the other hand, don't allow negative numbers.
Because it's all just about memory, in the end all the numerical values are stored in binary. A 32 bit unsigned integer can contain values from all binary 0s to all binary 1s. When it comes to 32 bit signed integer, it means one of its bits (most significant) is a flag, which marks the value to be positive or negative. So, it's the interpretation issue, which tells that value is signed.
Positive signed values are stored the same way as unsigned values, but negative numbers are stored using two's complement method.
If you want to write negative value in binary, first write positive number, next invert all the bits and last add 1. When a negative value in two's complement is added to a positive number of the same magnitude, the result will be 0.
In the example below lets deal with 8-bit numbers, because it'll be simple to inspect:
positive 95: 01011111
negative 95: 10100000 + 1 = 10100001 [positive 161]
0: 01011111 + 10100001 = 100000000
^
|_______ as we're dealing with 8bit numbers,
the 8 bits which means results in 0
The table is missing the minuses. The range of signed char is -128 to +127; likewise for the other types on the table.
It was a typo in the book; signed char goes from -128 to 127.
Signed integers are stored using the two's complement representation, in which the first bit is used to indicate the sign.
In C, chars are just 8 bit integers. This means that they can go from -(2^7) to 2^7 - 1. That's because we use the 7 last bits for the number and the first bit for the sign. 0 means positive and 1 means negative (in two's complement representation).
The biggest positive 7 bit number is (01111111)b = 2^7 - 1 = 127.
The smallest negative 7 bit number is (11111111)b = -128
(because 11111111 is the two's complement of 10000000 = 2^7 = 128).
Unsigned chars don't have signs so they can use all the 8 bits. Going from (00000000)b = 0 to (11111111)b = 255.
Signed numbers are those that have either + or - appended with them.
E.g +2 and -6 are signed numbers.
Signed Numbers can store both positive and negative numbers thats why they have bigger range.
i.e -32768 to 32767
Unsigned numbers are simply numbers with no sign with them. they are always positive. and their range is from 0 to 65535.
Hope it helps
Signed usually means the number has a + or - symbol in front of it. This means that unsigned int, unsigned shorts, etc cannot be negative.
Nobody mentioned this, but range of int in table is wrong:
it is
-2^(31) to 2^(31)-1
i.e.,
-2,147,483,648 to 2,147,483,647
A signed integer can have both negative and positive values. While a unsigned integer can only have positive values.
For signed integers using two's complement , which is most commonly used, the range is (depending on the bit width of the integer):
char s -> range -128-127
Where a unsigned char have the range:
unsigned char s -> range 0-255
First, your table is wrong... negative numbers are missing. Refering to the type char.... you can represent at all 256 possibilities as char has one byte means 2^8. So now you have two alternatives to set ur range. either from -128 to +128 or 0 to 255. The first one is a signed char the second a unsigned char. If you using integers be aware what kind of operation system u are using. 16 bit ,32 bit or 64 bit. Int (16 bit,32 bit,64 bit). char has always just 8 bit value.
It means that there will likely be a sign ( a symbol) in front of your value (+12345 || -12345 )

What are the max and min numbers a short type can store in C?

I'm having a hard time grasping data types in C. I'm going through a C book and one of the challenges asks what the maximum and minimum number a short can store.
Using sizeof(short); I can see that a short consumes 2 bytes. That means it's 16 bits, which means two numbers since it takes 8 bits to store the binary representation of a number. For example, 9 would be 00111001 which fills up one bit. So would it not be 0 to 99 for unsigned, and -9 to 9 signed?
I know I'm wrong, but I'm not sure why. It says here the maximum is (-)32,767 for signed, and 65,535 for unsigned.
short int, 2 Bytes, 16 Bits, -32,768 -> +32,767 Range (16kb)
Think in decimal for a second. If you have only 2 digits for a number, that means you can store from 00 to 99 in them. If you have 4 digits, that range becomes 0000 to 9999.
A binary number is similar to decimal, except the digits can be only 0 and 1, instead of 0, 1, 2, 3, ..., 9.
If you have a number like this:
01011101
This is:
0*128 + 1*64 + 0*32 + 1*16 + 1*8 + 1*4 + 0*2 + 1*1 = 93
So as you can see, you can store bigger values than 9 in one byte. In an unsigned 8-bit number, you can actually store values from 00000000 to 11111111, which is 255 in decimal.
In a 2-byte number, this range becomes from 00000000 00000000 to 11111111 11111111 which happens to be 65535.
Your statement "it takes 8 bits to store the binary representation of a number" is like saying "it takes 8 digits to store the decimal representation of a number", which is not correct. For example the number 12345678901234567890 has more than 8 digits. In the same way, you cannot fit all numbers in 8 bits, but only 256 of them. That's why you get 2-byte (short), 4-byte (int) and 8-byte (long long) numbers. In truth, if you need even higher range of numbers, you would need to use a library.
As long as negative numbers are concerned, in a 2's-complement computer, they are just a convention to use the higher half of the range as negative values. This means the numbers that have a 1 on the left side are considered negative.
Nevertheless, these numbers are congruent modulo 256 (modulo 2^n if n bits) to their positive value as the number really suggests. For example the number 11111111 is 255 if unsigned, and -1 if signed which are congruent modulo 256.
The reference you read is correct. At least, for the usual C implementations where short is 16 bits - that's not actually fixed in the standard.
16 bits can hold 2^16 possible bit patterns, that's 65536 possibilities. Signed shorts are -32768 to 32767, unsigned shorts are 0 to 65535.
This is defined in <limits.h>, and is SHRT_MIN & SHRT_MAX.
Others have posted pretty good solutions for you, but I don't think they have followed your thinking and explained where you were wrong. I will try.
I can see that a short consumes 2 bytes. That means it's 16 bits,
Up to this point you are correct (though short is not guaranteed to be 2 bytes long like int is not guaranteed to be 4 — the only guaranteed size by standard (if I remember correctly) is char which should always be 1 byte wide).
which means two numbers since it takes 8 bits to store the binary representation of a number.
From here you started to drift a bit. It doesn't really take 8 bits to store a number. Depending on a number, it may take 16, 32 64 or even more bits to store it. Dividing your 16 bits into 2 is wrong. If not a CPU implementation specifics, we could have had, for example, 2 bit numbers. In that case, those two bits could store values like:
00 - 0 in decimal
01 - 1 in decimal
10 - 2 in decimal
11 - 3 in decimal
To store 4, we need 3 bits. And so the value would "not fit" causing an overflow. Same applies to 16-bit number. For example, say we have unsigned "255" in decimal stored in 16-bits, the binary representation would be 0000000011111111. When you add 1 to that number, it becomes 0000000100000000 (256 in decimal). So if you had only 8 bits, it would overflow and become 0 because the most significant bit would have been discarded.
Now, the maximum unsigned number you can in 16 bits memory is — 1111111111111111, which is 65535 in decimal. In other words, for unsigned numbers - set all bits to 1 and that will yield you the maximum possible value.
For signed numbers, however, the most significant bit represents a sign — 0 for positive and 1 for negative. For negative, the maximum value is 1000000000000000, which is -32678 in base 10. The rules for signed binary representation are well described here.
Hope it helps!
The formula to find the range of any unsigned binary represented number:
2 ^ (sizeof(type)*8)

Resources