Seven bit and two compliment - twos-complement

If we use seven-bit two's complement binary representation for integers, what is
The number of integers (things) that can be represented in this way?
The smallest (most) negative integer that can be represented in this way?
The largest positive integer that can be represented in this way?
This is a CS homework question that I am having trouble answering and explaining. Any help would be appreciated.

So its really easy
Counting in binary usually goes like
>00000000 (8) = 0
>00000001 (8) = 1
>00000010 (8) = 2
>00000011 (8) = 3
>etc...etc.
In 7 bit the last bit is what decides if its a negative or positive
1 being negative and 0 being positive
> 10000000 = -128
> 10000001 = -127
> 10000010 = -126
> On...and on...
> 11111111 = -1
> 00000000 = 0
> 00000001 = 1
> 01111111 = 127
So lowest you can go is -128
Highest you can go is 127

Approved answer is not correct.
With 7-bits of 2's complement, it could range from -64 to 63. (traditionally, 7 bits can only go up to 2^n-1 which is 128 but MSB is reserved for sign, so we could have 6 bits to represent the data.
We will be getting 64 positive and 63 negative values and answer should be -64, 63.)
No, because in two's complement, the most significant bit is the sign bit. 0000001 is +1, a positive number.
That is why the range of two's complement 7-bit numbers is -64 to 63, because 64 is not representable (it would be negative number otherwise).
The most negative number is 1000000. The leading 1 tells you it's negative, and to get the magnitude of the number, you flip all the bits (0111111), then add one (1000000 = 64). So the resulting number is -64 thru 63.

For largest positive integer in 2's complement use the formula
(2^(n-1)-1)
That is (2^(7-1)-1)=63
For the smallest use
-2^n-1
That is -2^7-1=-64

Related

How come 129, which is 8-bit number, is stored as -127 in signed char in c++

I declared signed char and stored 129, an 8-bit number, in it. when typecasted it into integer and printed the result, its -127. I understand that it is overflow, but the confusion occurs when you look at the binary of 129 which is 10000001. In signed char, most significant bit is reserved as a sign bit and rest of the 7 bits are used to store the number's binary. According to this concept, 129 should be stored as -1. MSG representing negative sign and rest of the 7-bits are 0000001 which makes 1.
How come 129 becomes -127 when the binary of 129 makes -1.
#include <iostream>
using namespace std;
int main() {
char a=129;
cout<<(int) a; // OUTPUT IS -127
return 0;
}
Your current idea of negative numbers is like this:
00000001 == 1
10000001 == -1
01111111 == 127
11111111 == -127
This means that you have only available range of integers -127...127 and
also you have two zeros. (00000000 == 0 and 10000000 == -0)
Best method is so called two's complement. For any number x, you negate binary representation and add 1 to get -x.
It means:
00000001 == 1
11111111 == -1
01111111 == 127
10000001 == -127
10000000 == -128
In this way only 00000000 is zero and you have the widest range -128...127.
Also CPU don't need additional instructions for adding signed numbers because it's identical to unsigned number addition and subtraction.
You may wonder, why to add 1. Without it, it's called one's complement.
https://en.wikipedia.org/wiki/Ones%27_complement
Every current computer stores low level signed integers in a format known as two's complement.
In two's complement, MAX_POSITIVE+1 is MIN_NEGATIVE.
0x00000000 is 0.
0x00....0V is V.
0x01....11 is MAX_POSITIVE
0x10....00 is MIN_NEGATIVE
0x11....11 is -1.
This looks weird at first glance.
But, it means that the logic of addition for positive and negative numbers is the same. In fact, signed and unsigned math works out to be the same, except on overflow a positive signed number becomes a negative number, while the overflow of a positive unsigned number wraps around to 0.
Note that in C++, overflowing a signed number is undefined behavior, not because the hardware traps it, but because by making it UB the compiler is free to assume "adding positive numbers together is positive". But at the machine code level, the implementation is 2s complement, and C++ has defined converting from signed to unsigned as following the 2s complement assumption.

Why do negative numbers in variables have a larger limit than a positive number (signed variables)?

As seen in the picture above all of the variables have a negative limit that is one more than the positive limit. I was how it is able to add that extra one. I know that the first digit in the variable is used to tell if it is negative (1) or if is not (0). I also know that binary is based on the powers of 2. What I am confused about is how there is one extra when the positive itself can't go higher and the negative only has one digit changing. For example, a short can go up to 32,767 (01111111 11111111) or 16,383 + all of the decimal values of the binary numbers below it. Negative numbers are the same thing except a one at the beginning, right? So how do the negative numbers have a larger limit? Thanks to anyone who answers!
The reason is a scheme called "2's complement" to represent signed integer.
You know that the most significant bit of a signed integer represent the sign. But what you don't know is, it also represent a value, a negative value.
Take a 4-bit 2's complement signed integer as an example:
1 0 1 0
-2^3 2^2 2^1 2^0
This 4-bit integer is interpreted as:
1 * -2^3 + 0 * 2^2 + 1 * 2^1 + 0 * 2^0
= -8 + 0 + 2 + 0
= -6
With this scheme, the max of 4-bit 2's complement is 7.
0 1 1 1
-2^3 2^2 2^1 2^0
And the min is -8.
1 0 0 0
-2^3 2^2 2^1 2^0
Also, 0 is represented by 0000, 1 is 0001, and -1 is 1111. Comparing these three numbers, we can observe that zero has its "sign bit" positive, and there is no "negative zero" in 2's complement scheme. In other words, half of the range only consists of negative number, but the other half of the range includes zero and positive numbers.
If integers are stored using two's complement then you get one extra negative value and a single zero. If they are stored using one's complement or signed magnitude you get two zeros and the same number of negative values as positive ones. Floating point numbers have their own storage scheme, and under IEEE formats use have an explicit sign bit.
I know that the first digit in the variable is used to tell if it is negative (1) or if is not (0).
The first binary digit (or bit), yes, assuming two's complement representation. Which basically answers your question. There are 32,768 numbers < 0 (-32,768 .. -1) , and 32,768 numbers >= 0 (0 .. +32,767).
Also note that in binary the total possible representations (bit patterns) are an even number. You couldn't have the min and max values equal in absolute values, since you'd end up with an odd number of possible values (counting 0). Thus, you'd have to waste or declare illegal at least one bit pattern.

How to check IEEE754 overflow range

consider multipling 2 floating point numbers a and b
Let say expA=127, expB = 10
multplying significands give 1.101 x 2^137
so 137 >= 127 >= -126 so there is overflow
if -126 >= resultExp so there is underflow
here I am not sure how to get 127 and -126
127 (because 01111111?)
-126 (because 10000010?) why not 10000000
what if exp is 5 bit? 01111 >= x >= 10010 ?
The exponent section in floating point, at least in IEEE 754, is not represented in 2's complement as you mentioned, it is represented as follows:
Let us assume that the exponent section is of width n:
All zeroes, 000...000, i.e. Zero, represent denormals as well as +ve or -ve Zeroes in floating point.
The next representation, 000...001, i.e. One represents the least possible exponent, i.e. -126 in single-precision, that means that 0000...010 represents -125, 000...011 represents -124 and son on.
111...110 represents the maximum exponent, i.e. 127 in single-precision.
111...111 represents overflow and NaN representations.
see this: IEEE-754 specs
so you know what bits to extract
this C++ code should work
int e;
float f=1.5e+34;
unsigned int u;
u=((unsigned int*)((void*)(&f)))[0];
e=(u>>23)&&255;
if (e==255); // +/-Inf,NaN...
else if (e==0) e-=128; // denormalized
else e-=127; // normalized
in e is exponent of float f
also do not forget that the mantisa's multiplication can lower the result's exponent by 1
and for denormalized numbers even more
So the solution for a*b=c is:
set a0 as a but set its exponent to 0
set b0 as b but set its exponent to 0
compute c0=a0*b0
compute the result exponent
add the c0's exponent change to it
now you can test for over/underflow safely

How does C++ do bitwise "or" operations on negative numbers?

When I give to a variable such value: e = 17|-15; , I get -15 as an answer after compiling.I can't understand what arithmetic c++ uses. How does it perform a bit-wise OR operation on negative decimals?
It's just doing the operation on the binary representations of your numbers. In your case, that appears to be two's complement.
17 -> 00010001
-15 -> 11110001
As you can see, the bitwise OR of those two numbers is still -15.
In your comments above, you indicated that you tried this with the two's complement representations, but you must have done something wrong. Here's the step by step:
15 -> 00001111 // 15 decimal is 00001111 binary
-15 -> ~00001111 + 1 // negation in two's complement is equvalent to ~x + 1
-15 -> 11110000 + 1 // do the complement
-15 -> 11110001 // add the 1
It does OR operations on negative numbers the same way it does so on positive numbers. The numbers are almost certainly represented in two's-complement form, which gives you these values:
17 = 0000000000010001
-15 = 1111111111110001
As you can see, all the bits of 17 are already set in −15, so the result of combining them is again −15.
A bitwise or with a negative number works JUST like a bitwise or with a positive number. The bits in one number are ored with the bits in the other number. How your processor represents negative numbers is a different matter. Most use something called "two's complement", which is essentially "invert the number and add 1".
So, if we have, for simplicity, 8 bit numbers:
15 is 00001111
Inverted we get 11110000
Add one 11110001
17 is 00010001
Ored together 11110001
17 = b00010001
-15 = b11110001 <--- 2s complement
| -15 = b11110001
The operator | is a "bitwise OR" operator, meaning that every bit in the target is computed as the OR-combination of the corresponding bits in the two operands. This means, that a bit in the result is 1 if any of the two bits in the numbers at the same positions are 1, otherwise 0.
Clearly, the result depends on the binary representation of the numbers which again depends on the platform.
Almost all platforms use the Two's complement, which can be thought as a circle of unsigned numbers, in which negative numbers are just in the opposite direction than positive numbers and "wrap around" the circle.
Unsigned integers:
Signed integers:
The calculation of your example is as follows.
17: 00000000 00000000 00000000 00010001
-15: 11111111 11111111 11111111 11110001
------------------------------------------
-15: 11111111 11111111 11111111 11110001
you have to looks at how the bits work
Basically, if either number has a 1 in a particular spot, than the result will also have a 1
-15 : 11110001 (two's complement)
17 : 00010001
-15 | 17 : 11110001
as you can see, the result is the same as -15

Negation of -2147483648 not possible in C/C++?

#include <iostream>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int num=-2147483648;
int positivenum=-num;
int absval=abs(num);
std::cout<<positivenum<<"\n";
std::cout<<absval<<"\n";
return 0;
}
Hi I am quite curious why the output of the above code is
-2147483648
-2147483648
Now I know that -2147483648 is the smallest represntable number among signed ints, (assuming an int is 32 bits). I would have assumed that one would get garbage answers only after we went below this number. But in this case, +2147483648 IS covered by the 32 bit system of integers. So why the negative answer in both cases?
But in this case, +2147483648 IS covered by the 32 bit system of integers.
Not quite correct. It only goes up to +2147483647. So your assumption isn't right.
Negating -2147483648 will indeed produce 2147483648, but it will overflow back to -2147483648.
Furthermore, signed integer overflow is technically undefined behavior.
The value -(-2147483648) is not possible in 32-bit signed int. The range of signed 32-bit int is –2147483648 to 2147483647
Ahhh, but its not... remember 0, largest signed is actually 2147483647
Because the 2's complement representation of signed integers isn't symmetric and the minimum 32-bit signed integer is -2147483648 while the maximum is +2147483647. That -2147483648 is its own counterpart just as 0 is (in the 2's complement representation there's only one 0, there're no distinct +0 and -0).
Here's some explanation.
A negative number -X when represented as N-bit 2's complement, is effectively represented as unsigned number that's equal to 2N-X. So, for 32-bit integers:
if X = 1, then -X = 232 - 1 = 4294967295
if X = 2147483647, then -X = 232 - 2147483647 = 2147483649
if X = 2147483648, then -X = 232 - 2147483648 = 2147483648
if X = -2147483648, then -X = 232 + 2147483648 = 2147483648 (because we only keep low 32 bits)
So, -2147483648 = +2147483648. Welcome to the world of 2's complement values.
The previous answers have all pointed out that the result is UB (Undefined Behaviour) because 2147483648 is not a valid int32_t value. And we all know, UB means anything can happen, including having daemons flying out of your nose. The question is, why does the cout behavior print out a negative value, which seems to be the worst value it could have chosen randomly ?
I'll try to justify it on a two's complement system. Negation on a CPU is actually somewhat of a tricky operation. You can't do it in one step. One way of implementing negation, i.e. int32_t positivenum = -num is to do a bit inversion followed by adding 1, i.e. int32_t positivenum = ~num + 1, where ~ is the bitwise negation operator and the +1 is to fix the off-by-one error. For example, negation of 0x00000000 is 0xFFFFFFFF + 1 which is 0x00000000 (after roll over which is what most CPUs do). You can verify that this works for most integers... except for 2147483648. 2147483648 is stored as 0x80000000 in two's complement. When you invert and add one, you get
- (min) = -(0x80000000)
= ~(0x80000000) + 1
= 0x7FFFFFFF + 1
= 0x80000000
= min
So magically, the unary operator - operating on min gives you back min!
One thing that is not obvious is that two-complement CPUs' arithmetic have no concept of positive or negative numbers! It treats all numbers as unsigned under the hood. There is just one adder circuit, and one multiplier circuit. The adder circuit works for positive and negative numbers, and the multiplier circuit works for positive and negative number.
Example: -1 * -1
= -1 * -1
= (cast both to uint32_t)
= 0xFFFFFFFF * 0xFFFFFFFF
= FFFFFFFE00000001 // if you do the result to 64 bit precision
= 0x00000001 // after you truncate to 32 bit precision
= 1
The only time you care about signed vs unsigned is for comparisons, like < or >.