Two's complement detect overflow with carries - overflow

If I add two signed binary numbers with Two's Complement method, why does it automatically mean that overflow has occoured if the carry into the MSB (the sign) and the carry out are not the same?

Let's take one fact out of the way.
When we add a negative and a positive operand, the result will always be in the range of representation. Overflows occur when we add two numbers with the same sign (both positive or both negative) and the result has the opposite sign.
When we add numbers in two's complement, we add the sign bit of the first operand with the sign bit of second operand.
When we add positive + positive operands, the sum of the sign bits is 0.
0XXX (positive)
+ 0XXX (positive)
------
0XXX (positive)
That means that it doesn't matter what happens, there will NEVER be a carry-out when adding positive + positive operands.
So, if there is a carry-on into the sign bits
1
0XXX (positive)
+ 0XXX (positive)
------
1XXX (negative)
That carry-on bit 1 will become the sign of the result. That means that we added two positive operands and we got a negative number as a result.
Carry-out = 0
Carry-on sign bit = 1
OVERFLOW!
When we add negative + negative operands, the sum of the sign bits is 0 with a carry-out.
1XXX (negative)
+ 1XXX (negative)
------
10XXX (positive)
That means that it doesn't matter what happens, there will ALWAYS be a carry-out when adding negative + negative operands. Note that by "default" the result would be a positive number. It "needs" that carry-on to adjust the result to the same sign of the operands. If there is a carry-on into the sign bit, we will have two negative operands with a negative result.
So, if there is no carry-on into the sign bits
0
1XXX (negative)
+ 1XXX (negative)
------
10XXX (positive)
That carry-on bit 0 will become the sign of the result. That means that we added two negative operands and we got a positive number as a result.
Carry-out = 1
Carry-on sign bit = 0
OVERFLOW!

Related

How to perform a bitwise round up to even numbers if odd?

How to perform a bitwise only (shifts,and,or,xor..) round up to even numbers if the number is odd (also for negative numbers)?
Example:
Input: 3; Output: 4
Input: 4; Output: 4
Input: 5; Output: 6
Input: 6; Output: 6
Input: -14; Output: -14
Input: -15; Output: -14
What I tried: This works so far, but it seems to be kinda redundant?
(((n + 1) >> 1) << 1)
Is there a shorter solution?
A solution is to add the least significant bit to the number :
n+(n&1)
If n is even, its LSB is 0, and the number is unchanged as expected.
If n is odd, its LSB is 1 and n will be changed to the even number immediately above it.
This is based on an arithmetic operations and will work, for either positive and negative numbers.
It does not even rely on the fact that numbers are coded in two's complement. The only real assumption is that even numbers have a LSB at 0 and odd numbers a LSB at 1. If n is coded in an unusual way, this method should still work, provided this assumption is verified. For instance, with numbers coded in sign-absolute value or with excess code (with the excess even).
Your method, while correct on most computers, realizes ((n+1)&div;2)×2 by means of right and left shifts. But the C or C++ standards leave (for the moment) implementation dependent the meaning of right shifts on signed integers and your code may break for negative numbers on some unusual architectures/compilers.

Bit representation using excess-3 and mantissa

If a float number is stored in one byte such that the first bit is the sign, the next three bits represent the exponent in excess-3 notation and the last four bits represent the mantissa, then the bit pattern 00100100 represents?
I understand that number will positive as the first bit is 0, I also understand that 010 excess-3 is -1 and 0100 is 4, but how do I get a float number having all these?
normalized binary floating point numbers are of the form (+/-) 1.mmm... * 2^exp, where mmm... represents the digits of the mantissa.
beware that the mantissa (0100) is the fractional part of the normalized number, so it is 1.0100, which is not 4.
putting it all together will give
+1.0100 * 2^-1
which is 0.101

Understanding two's complement

I'm trying to understand two's complement:
Does two's complement mean that this number is invalid:
1000
Does two's complement disallow the use of the most significant bit for positive numbers. Ie. Could
1000
Ever represent 2^3? Or would it represent -0?
I'm also confused about why you need to add 1 to a one's complement.
in two's complement the MSB (most significant bit) is set to one for negatives. to multiply by -1 a two's complement number you well do the following:
add one to the number.
reverse all bits after the first one.
for example:
the number 10010 after adding one you well get: 10011 after reversing you get: 01101.
that means that 10010 is negative 13.
the number 1000 after adding one is: 1001 after reversing: 0111. that means that 1000 is negative 7.
now, to your last question: no. if you work with two's complement you can't use the MSB for positive numbers. but, you could define you are not using two's complement and use higher positive numbers.
Twos-complement is based on two requirements:
numbers are represented by a fixed number of bits;
x + -x = 0.
Assuming a four bit representation, say, we have
0 + -0 = 0000 + -0000 (base 2) = 0000 => -0000 = 0000
1 + -1 = 0001 + -0001 (base 2) = 0000 => -0001 = 1111 (carry falls off the end)
Now we have our building blocks, a drop of induction will show you the "flip the bits and add 1" algorithm is exactly what you need to convert a positive number to its twos-complement negative representation.
2's complement is mostly a matter of how you interpret the value, most math* doesn't care whether you view a number as signed or not. If you're working with 4 bits, 1000 is 8 as well as -8. This "odd symmetry" arises here because adding it to a number is the same as xoring it with a number (since only the high bit is set, so there is no carry into any bits). It also arises from the definition of two's complement - negation maps this number to itself.
In general, any number k represents the set of numbers { a | a = xk mod n } where n is 2 to the power of how many bits you're working with. This perhaps somewhat odd effect is a direct result of using modular arithmetic and is true whether you view number as signed or unsigned. The only difference between the signed and unsigned interpretations is which number you take to be the representative of such a set. For unsigned, the representative is the only such a that lies between 0 and n. For signed numbers, the representative is the only such a that lies between -(n/2) and (n/2)-1.
As for why you need to add one, the goal of negation is to find an x' such that x' + x = 0. If you only complemented the bits in x but didn't add one, x' + x would not have carries at any position and just sum to "all ones". "All ones" plus 1 is zero, so adding one fixes x' so that the sum will go to zero. Alternatively (well it's not really an alternative), you can take ~(x - 1), which gives the same result as ~x + 1.
*Signedness affects the result of division, right shift, and the high half of multiplication (which is rarely used and, in many programming languages, unavailable anyway).
It depends on how many bits you use to represent numbers.
The leftmost (largest) bit has a value of -1*(2**N-1) or in this case, -8. (N being the number of bits.) Subsequent bits are their normal values.
So
1000
is -8
1111
is -1
0111
is 7.
However, if you have 8 bits these become different values!
0000 1000
is positive 8. Only the leftmost bit adds a negative value to the answer.
In either case, the range of numbers is from
1000....0
for -2**(N-1) with N bits
to
0111....1
Which is 2**(N-1) -1. (This is just normal base 2 since the leftmost bit is 0.)

Google Protocol Buffers: ZigZag Encoding

From "Signed Types" on Encoding - Protocol Buffers - Google Code:
ZigZag encoding maps signed integers to unsigned integers so that numbers with a small absolute value (for instance, -1) have a small varint encoded value too. It does this in a way that "zig-zags" back and forth through the positive and negative integers, so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so on, as you can see in the following table:
Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295
In other words, each value n is encoded using
(n << 1) ^ (n >> 31)
for sint32s, or
(n << 1) ^ (n >> 63)
for the 64-bit version.
How does (n << 1) ^ (n >> 31) equal whats in the table? I understand that would work for positives, but how does that work for say, -1? Wouldn't -1 be 1111 1111, and (n << 1) be 1111 1110? (Is bit-shifting on negatives well formed in any language?)
Nonetheless, using the fomula and doing (-1 << 1) ^ (-1 >> 31), assuming a 32-bit int, I get 1111 1111, which is 4 billion, whereas the table thinks I should have 1.
Shifting a negative signed integer to the right copies the sign bit, so that
(-1 >> 31) == -1
Then,
(-1 << 1) ^ (-1 >> 31) = -2 ^ -1
= 1
This might be easier to visualise in binary (8 bit here):
(-1 << 1) ^ (-1 >> 7) = 11111110 ^ 11111111
= 00000001
Another way to think about zig zag mapping is that it is a slight twist on a sign and magnitude representation.
In zig zag mapping, the least significant bit (lsb) of the mapping indicates the sign of the value: if it's 0, then the original value is non-negative, if it's 1, then the original value is negative.
Non-negative values are simply left shifted one bit to make room for the sign bit in the lsb.
For negative values, you could do the same one bit left shift for the absolute value (magnitude) of the number and simply have the lsb indicate the sign. For example, -1 could map to 0x03 or 0b00000011, where the lsb indicates that it is negative and the magnitude of 1 is left shifted by 1 bit.
The ugly thing about this sign and magnitude representation is "negative zero," mapped as 0x01 or 0b00000001. This variant of zero "uses up" one of our values and shifts the range of integers we can represent by one. We probably want to special case map negative zero to -2^63, so that we can represent the full 64b 2's complement range of [-2^63, 2^63). That means we've used one of our valuable single byte encodings to represent a value that will very, very, very rarely be used in an encoding optimized for small magnitude numbers and we've introduced a special case, which is bad.
This is where zig zag's twist on this sign and magnitude representation happens. The sign bit is still in the lsb, but for negative numbers, we subtract one from the magnitude rather than special casing negative zero. Now, -1 maps to 0x01 and -2^63 has a non-special case representation too (i.e. - magnitude 2^63 - 1, left shifted one bit, with lsb / sign bit set, which is all bits set to 1s).
So, another way to think about zig zag encoding is that it is a smarter sign and magnitude representation: the magnitude is left shifted one bit, the sign bit is stored in the lsb, and 1 is subtracted from the magnitude of negative numbers.
It is faster to implement these transformations using the unconditional bit-wise operators that you posted rather than explicitly testing the sign, special case manipulating negative values (e.g. - negate and subtract 1, or bitwise not), shifting the magnitude, and then explicitly setting the lsb sign bit. However, they are equivalent in effect and this more explicit sign and magnitude series of steps might be easier to understand what and why we are doing these things.
I will warn you though that bit shifting signed values in C / C++ is not portable and should be avoided. Left shifting a negative value has undefined behavior and right shifting a negative value has implementation defined behavior. Even left shifting a positive integer can have undefined behavior (e.g. - if you shift into the sign bit it might cause a trap or something worse). So, in general, don't bit shift signed types in C / C++. "Just say no."
Cast first to the unsigned version of the type to have safe, well-defined results according to the standards. This does mean that you then won't have arithmetic shift of negative values (i.e. - dragging the sign bit to the right) -- only logical shift, so you need to adjust the logic to account for that.
Here are the safe and portable versions of the zig zag mappings for 2's complement 64b integers in C:
#include <stdint.h>
uint64_t zz_map( int64_t x )
{
return ( ( uint64_t ) x << 1 ) ^ -( ( uint64_t ) x >> 63 );
}
int64_t zz_unmap( uint64_t y )
{
return ( int64_t ) ( ( y >> 1 ) ^ -( y & 0x1 ) );
}
Note the arithmetic negation of the sign bit in the right hand term of the XORs. That yields either 0 for non-negatives or all 1's for negatives -- just like arithmetic shift of the sign bit from msb to lsb would do. The XOR then effectively "undoes" / "redoes" the 2's complementation minus 1 (i.e. - 1's complementation or logical negation) for negative values without any conditional logic or further math.
Let me add my two cents to the discussion. As other answers noted, the zig-zag encoding can be thought as a sign-magnitude twist. This fact can be used to implement conversion functions which work for arbitrary-sized integers.
For example, I use the following code in one on my Python projects:
def zigzag(x: int) -> int:
return x << 1 if x >= 0 else (-x - 1) << 1 | 1
def zagzig(x: int) -> int:
assert x >= 0
sign = x & 1
return -(x >> 1) - 1 if sign else x >> 1
These functions work despite Python's int has no fixed bitwidth; instead, it extends dynamically. However, this approach may be inefficient in compiled languages since it requires conditional branching.

Using bit manipulation to tell if an unsigned integer can be expressed in the form 2^n-1

To test if an unsigned integer is of the form 2^n-1 we use:
x&(x+1)
What is that supposed to equal? That is,
x&(x+1) == ?
A number of the form 2^n-1 will have all of the bits up to the nth bit set. For example, 2^3-1 (7) is:
0b0111
If we add one to this, we get 8:
0b1000
Then, performing a bitwise and, we see that we get zero, because no bit is set on in both numbers. If we start with a number not of the form 2^n+1, then the result will be nonzero.
In complement to the existing answers, here is a short explanation of why numbers x that are not of the form 0b00000 (zero) or 0b0111..11 (all lowest digits set, these are all the numbers 2^n-1 for n>0) do not have the property x&(x+1) == 0.
For a number x of the form 0b????1000..00, x+1 has the same digits as x except for the least significant bit, so x & (x+1) has at least one bit set, the bit that was displayed as being set in x. By way of shorter explanation:
x 0b????1000..00
x+1 0b????1000..01
x&(x+1) 0b????10000000
For a number x of the form 0b????10111..11:
x 0b????10111..11
x+1 0b????110000000
x&(x+1) 0b????10000..00
In conclusion, if x is not either zero or written in binary with all lowest digits set, then x&(x+1) is not zero.
Zero. If X is 2^N-1, it is an unbroken string of 1's in binary. One more than that is a 1 followed by a string of zeroes same length as X, so the two numbers have no 1 bits in common in any location, so the AND of the two is zero.

Resources