When performing bitwise subtraction using two's complement, how does one know when the overflow should be ignored? Several websites I read stated that the overflow is simply ignored, but that does not always work -- the overflow is necessary for problems like -35 - 37, as an extra digit is needed to express the answer of -72.
EDIT: Here's an example, using the above equation.
35 to binary -> 100011, find two's complement to make it negative: 011101
37 to binary -> 100101, find two's complement to make it negative: 011011
Perform addition of above terms (binary equivalent of -35 - 37):
011101
011011
------
111000
Take two's complement to convert back to positive: 001000
The above is what many websites (including academic ones) say the answer should be, as you ignore overflow. This is clearly incorrect, however.
An overflow happens when the result cannot be represented in the target data type. The value -72 can be represented in a char, which is a signed 8-bit quantity... there is no overflow in your example. Perhaps you are thinking about a borrow while doing bitwise subtraction... when you subtract a '1' from a '0' you need to borrow from the next higher order bit position. You cannot ignore borrows when doing subtraction.
-35 decimal is 11011101 in two's complement 8-bit
+37 decimal is 00100101 in two's complement 8-bit
going right to left from least significant to most significant bit you can subtract each bit in +37 from each bit in -35 until you get to bit 5 (counting starts at bit 0 on the right). At bit position 5 you need to subtract '1' from '0' so you need to borrow from bit position 6 (the next higher order bit) in -35, which happens to be a '1' prior to the borrow. The result looks like this
-35 decimal is 11011101 in two's complement 8-bit
+37 decimal is 00100101 in two's complement 8-bit
--------
-72 decimal is 10111000 in two's complement 8-bit
The result is negative, and your result in 8-bit two's complement has the high order bit set (bit 7)... which is negative, so there is no overflow.
Update:I think I see where the confusion is, and I claim that the answer here Adding and subtracting two's complement is wrong when it says you can discard the carry (indicates overflow). In that answer they do subtraction by converting the second operand to negative using two's complement and then adding. That's fine - but a carry doesn't represent overflow in that case. If you add two positive numbers in N bits (numbered 0 to N-1) and you consider this unsigned arithmetic range 0 to (2^N)-1 and you get a carry out of bit position N-1 then you have overflow - the sum of two positive numbers (interpreted as unsigned to maximize the range of representable positive numbers) should not generate a carry out of the highest order bit (bit N-1). So when adding two positive numbers you identify overflow by saying
there must be no carry out of bit N-1 when you interpret them as unsigned and
the result in bit N-1 must be zero when interpreted as signed (two's complement)
Note, however, that processors don't distinguish between signed and unsigned addition/subtraction... they set the overflow flag to indicate that if you are interpreting your data as signed then the result could not be represented (is wrong).
Here is a very detailed explanation of carry and overflow flag. The takeaway from that article is this
In unsigned arithmetic, watch the carry flag to detect errors.
In unsigned arithmetic, the overflow flag tells you nothing interesting.
In signed arithmetic, watch the overflow flag to detect errors.
In signed arithmetic, the carry flag tells you nothing interesting.
This is consistent with the definition of arithmetic overflow in Wikipedia which says
Most computers distinguish between two kinds of overflow conditions. A carry occurs when the result of an addition or subtraction, considering the operands and result as unsigned numbers, does not fit in the result. Therefore, it is useful to check the carry flag after adding or subtracting numbers that are interpreted as unsigned values. An overflow proper occurs when the result does not have the sign that one would predict from the signs of the operands (e.g. a negative result when adding two positive numbers). Therefore, it is useful to check the overflow flag after adding or subtracting numbers that are represented in two's complement form (i.e. they are considered signed numbers).
Related
I dont quite understand, if someone can provide examples to help me understand better. It would be greatly appreciated.
On a system using 2's complement and a 32-bit int, the range of values it can hold is -2147483648 to 2147483647.
If you were to negate the smallest possible int, i.e. -2147483648, the result would be 2147483648 which is out of range.
A sign-and-magnitude system cannot overflow in this way because 1 bit is reserved solely as a sign bit while the remaining bits (assuming no padding) are the value.
You can't get an overflow in sign-magnitude format. Negating the number simply inverts the sign and keeps the magnitude the same.
In two's complement, you get an overflow if you try to negate the most negative value, because there's always 1 more negative value than positive values. For instance, in 8 bits the range of values is -128 to 127. Since there's no 128, you get an overflow if you try to negate -128.
As 2's complement numbers do not have negative zero - they have only one zero so the number of the negative numbers is larger than the number of the positive numbers.
If you negate the minimum negative number you will get number which cannot be represented as a positive number of the same length.
I've done some quick tests that a signed int to unsigned int cast in C does not change the bit values (on an online debugger).
What I want to know is whether it is guaranteed by a C standard or just the common (but not 100% sure) behaviour ?
Conversion from signed int to unsigned int does not change the bit representation in two’s-complement C implementations, which are the most common, but will change the bit representation for negative numbers, including possible negative zeroes on one’s complement or sign-and-magnitude systems.
This is because the cast (unsigned int) a is not defined to retain the bits but the result is the positive remainder of dividing a by UINT_MAX + 1 (or as the C standard (C11 6.3.1.3p2) says,
the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
The two’s complement representation for negative numbers is the most commonly used representation for signed numbers exactly because it has this property of negative value n mapping to the same bit pattern as the mathematical value n + UINT_MAX + 1 – it makes it possible to use the same machine instruction for signed and unsigned addition, and the negative numbers will work because of wraparound.
Casting from a signed to an unsigned integer is required to generate the correct arithmetic result (the same number), modulo the size of the unsigned integer, so to speak. That is, after
int i = anything;
unsigned int u = (unsigned int)i;
and on a machine with 32-bit ints, the requirement is that u is equal to i, modulo 232.
(We could also try to say that u receives the value i % 0x100000000, except it turns out that's not quite right, because the C rules say that when you divide a negative integer by a positive integer, you get a quotient rounded towards 0 and a negative remainder, which isn't the kind of modulus we want here.)
If i is 0 or positive, it's not hard to see that u will have the same bit pattern.
If i is negative, and if you're on a 2's complement machine, it turns out the result is also guaranteed to have the same bit pattern. (I'd love to present a nice proof of that result here, but I don't have time just now to try to construct it.)
The vast majority of today's machines use 2's complement. But if you were on a 1's complement or sign/magnitude machine, I'm pretty sure the bit patterns would not always be the same.
So, bottom line, the sameness of the bit patterns is not guaranteed by the C Standard, but arises due to a combination of the C Standard's requirements, and the particulars of 2's complement arithmetic.
I'm trying to convert my 16 bit integer to two's complement if it's negative.
At the moment, I'm using the One's complement operator. I figure I can use that, and then add 1 to the binary value to convert it to two's complement. However, I'm unable to do x = ~a + 1 because that just yields the integer value + 1.
If my process is correct, how can I add 1 to the binary integer? If not, what is the most appropriate way to convert a 16 bit integer to 2's complement in Objective-C?
A two's complement is a kind of representation of signed numbers, not a value or an operation. On nearly all modern computers two's complements are the standard representation of signed integers. (And it is one of three allowed representations of integers in the standard.)
Therefore if you have any signed integral number, it is represented in two's complement. I think you want to have "the" two's complement of a positive number. This is simply the negative value, if your machine uses two's complements for signed numbers.
int positiveValue = 5;
int twosComplement = -positiveValue;
This question already has answers here:
What is the maximum and minimum values can be represented with 5-digit number? in 2's complement representation
(2 answers)
Closed 5 years ago.
I understand to get two's complement of an integer, we first flip the bits and add one to it but I'm having hard time figuring out Tmax and Tmin?
In a 8-bit machine using two's compliment for signed integers how would I find the maximum and minimum integer values it can hold?
would tmax be =01111111? and tmin =11111111?
You are close.
The minimum value of a signed integer with n bits is found by making the most significant bit 1 and all the others 0.
The value of this is -2^(n-1).
The maximum value of a signed integer with n bits is found by making the most significant bit 0 and all the others 1.
The value of this is 2^(n-1)-1.
For 8 bits the range is -128...127, i.e., 10000000...01111111.
Read about why this works at Wikipedia.
Due to an overflow that would lead to a negative zero, the binary representation for the smallest signed integer using twos complement representation is usually a one bit for the sign, followed by all zero bits.
If you divide the values in an unsigned type into two groups, one group for negative and another positive, then you'll end up with two zeros (a negative zero and a positive zero). This seems wasteful, so many have decided to give that a value. What value should it have? Well, it:
has a 1 for a sign bit, implying negative;
has a 1 for the most significant bit, implying 2width-1 (128, in your example)...
Combining these points to reinterpret that value as -128 seems to make sense.
This question already has answers here:
Arithmetic bit-shift on a signed integer
(6 answers)
Closed 9 years ago.
so, lets say I have a signed integer (couple of examples):
-1101363339 = 10111110 01011010 10000111 01110101 in binary.
-2147463094 = 10000000 00000000 01010000 01001010 in binary.
-20552 = 11111111 11111111 10101111 10111000 in binary.
now: -1101363339 >> 31 for example, should equal 1 right? but on my computer, I am getting -1. Regardless of what negative integer I pick if x = negative number, x >> 31 = -1. why? clearly in binary it should be 1.
Per C99 6.5.7 Bitwise shift operators:
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
where E1 is the left-hand side of the shift expression. So it depends on your compiler what you'll get.
In most languages when you shift to the right it does an arithmetic shift, meaning it preserves the most significant bit. Therefore in your case you have all 1's in binary, which is -1 in decimal. If you use an unsigned int you will get the result you are looking for.
Per C 2011 6.5.7 Bitwise shift operators:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type
or if E1 has a signed type and a nonnegative value, the value of the result is the integral
part of the quotient of E1/ 2E2. If E1 has a signed type and a negative value, the
resulting value is implementation-defined.
Basically, the right-shift of a negative signed integer is implementation defined but most implementations choose to do it as an arithmetic shift.
The behavior you are seeing is called an arithmetic shift which is when right shifting extends the sign bit. This means that the MSBs will carry the same value as the original sign bit. In other words, a negative number will always be negative after a left shift operation.
Note that this behavior is implementation defined and cannot be guaranteed with a different compiler.
What you are seeing is an arithmetic shift, in contrast to the bitwise shift you were expecting; i.e., the compiler, instead of "brutally" shifting the bits, is propagating the sign bit, thus dividing by 2N.
When talking about unsigned ints and positive ints, a right shift is a very simple operation - the bits are shifted to the right by one place (inserting 0 on the left), regardless of their meaning. In such cases, the operation is equivalent to dividing by 2N (and actually the C standard defines it like that).
The distinction comes up when talking about negative numbers. Several negative numbers representation exist, although currently for integers most commonly 2's complement representation is used.
The problem of a "brutal" bitwise shift here is, for starters, that one of the bits is used in some way to express the sign; thus, shifting the binary digits regardless of the negative integers representation can give unexpected results.
For example, commonly in 2's representation the most significant bit is 1 for negative numbers, 0 for positive numbers; applying a bitwise shift (with zeroes inserted to the left) to a negative number would (between other things) make it positive, not resulting in the (usually expected) division by 2N
So, arithmetic shift is introduced; negative numbers represented in 2's complement have an interesting property: the division by 2N behavior of the shift is preserved if, instead of inserting zeroes from the left, you insert bits that have the same value of the original sign bit.
In this way, signed divisions by 2N can be performed with just a bit of extra logic in the shift, without having to resort to a fully-fledged division routine.
Now, is arithmetic shift guaranteed for signed integers? In some languages yes1, but in C it's not like that - the behavior of the shift operators when dealing with negative integers is left as an implementation-defined detail.
As often happens, this is due to different hardware support for the operation; C is used on vastly different platforms, and, especially in the past, there was quite a difference in the "cost" of operations depending on the platform.
For example, if the processor does not provide an arithmetic right shift instruction, the compiler would be mandated to emit a much slower DIV instruction of some kind, which could be a problem in an inner loop on slower processors. For these reasons, the C standard leaves it up to the implementor to do the most appropriate thing for the current platform.
In your case, your implementation probably chose arithmetic shift because you are running on an x86 processor, that uses 2's complement arithmetic and provides both bitwise and arithmetic shift as single CPU instructions.
Actually, languages like Java even have separated arithmetic and bitwise shift operators - this is mainly due to the fact that they do not have unsigned types to e.g. store bitfields.