Binary subtraction is usually implemented using binary addition, and negation.
It is unusual to do three or more operations simultaneously (other than multiply add, aka multiply accumulate, or MAC).
So A-B-C
, is usually implemented as A+(-B)+(-C)
where the -
is unary minus, or negation.
This scales to many operands and many subtrahends.
A-B-C-D+E-F-G
becomes A+(-B)+(-C)+(-D)+E+(-F)+(-G)
. The addition, '+' operation is commutative, so this can be evaluated in any order (ignoring overflow), and with arbitrarily many operands.
How might we operate on \$47-15+23-11+16-22+12\$?
One approach might be \$47+23+16+12-(15+11+22)\$, but how much hardware might be needed to implement that?
Clearly a nifty solution is \$47+(16-15)+(23-22)+(16-15)=50\$, but so what? How much hardware or VHDL and programmable logic would it take to recognise that? When we know in advance the sequence of operations, then optimisations may make sense.
Using 1's complement representation, the rightmost, 'top' bit represents the sign, with '1' indicating a negative number. So to negate a number, 'invert' its top bit to be the other value. A problem with 1's complement representation is their are two zero's a positive (top bit 0) and a negative (top bit 1) representation, which makes some operations more complex.
Most computing uses 2's complement representation of binary numbers. The top bit still indicates the sign ('0' for positive, and '1' for negative) as in 1's complement. However, the values are represented in a slightly different way.
The process is described at Wikipedia Two's complement
To subtract a number, convert to its two's complement form then add. This is a bit weird, but isn't too bad to implement.
This approach has several useful properties:
- there is only one representation of zero, and hence
- comparing a number against zero is simpler than 1's complement
- once the number is converted to its complement, the addition is
Commutative, it
can be done is either order
Edit:
An efficient way to implement subtraction by calculating the 2's complement adding is:
- invert each bit of the subtrahend. Cost one NOT gate per bit. The
invert operation has quite a low propagation delay, then
- add using N-bit-addder with a '1' carry-in at the bottom bit. The
carry-in implements the second 2's complement step of +1.
So the total extra cost of subtraction is N NOT-gates, and the lowest bit of the N-bit-add is a full adder instead of a half adder (which is the classic way to teach this), and hence is an extra three gates.
A useful property of restricting operations to two operands at a time is it works for all cases, and is relatively easy to parse, and apply 'everyday' arithmetic rules of precedence (multiply before add), associativity (left to right) and commutativity (A+B = B+A, but A-B ≠ B-A).
Best Answer
You didnt state your "rules" so we dont know how to understand "new rules", complete solution, etc. If you use a flag based architecture then both C and V are important/desired. If not a flag based architecture you still compute them but do the comparison in the same instruction.
As you perhaps understand, in binary math, that first off you dont subtract you add
x - y = x + (-y) = x + (~y + 1) = x + (~y) + 1
and you might have figured out that the same logic is used for signed and unsigned addition/subtraction that is the beauty of twos complement. the logic/hardware doesnt care (multiply and divide are a different story with respect to signed/unsigned)
now is that 1 + 14 = 15 or is that 1 + -2 = -1? yes it is both at the same time the logic doesnt care, only the human cares if those are unsigned or signed numbers.
Now first off unsigned overflow
the carry out from the msbit is the carry out for the adder and indicates unsigned overflow if set. there isnt room to store the value but notice that if we were to look at this as -1 + 2 = 1 then there is no signed overflow. Two equivalent ways to determine signed overflow are. If the msbit of the operands (as viewed in the adder) is the same and the msbit of the result is different from the operands then it is an overflow otherwise not. So if the msbits of the operands different it is not a signed overflow if all three msbits are the same it is not a signed overflow otherwise it is. I find it easier to examine the carry in and carry out of the msbit, if they differ then it is a signed overflow if they match as in this case it is not.
so with 4 bits -4 = -100 = 1011 + 1 = 1100 so -4 - 5 = -9, -9 cannot be represented in 4 bits so
so we see that the msbits of the operands are 1, the msbit of the result is 0, signed overflow. we can also look at the carry in of the msbit (0) and the carry out of the msbit (1) and they dont match, signed overflow.
The carry/borrow bit is very useful to preserve no reason to discard. Already saw it above as a unsigned signed overflow. For subtraction it represents a borrow.
In grade school decimal math
you cant subtract 5 from 0 in that first column, so you have to borrow, in this case that borrow cascades its way all the way across to the left end where it borrows that 1 and we have 999999 - 5.
In grade school math we cant subtract 5 from 3 instead we subtract 3 from 5 then negate the result. But in binary logic we can subtract 5 from 3.
3 - 5 is -2 with a carry out of 0, what if we subtract 5 from 3 (different equation just using the same two numbers)
5 - 3 = 2. the carry out is a 1. you can work through all combinations, but the carry out for a subtract means not borrow.
So for subtraction you invert the second operand and invert or make 1 the carry in (invert and add 1). Some architectures invert the carry out for a subtract to call it a borrow bit, some simply leave the carry out as is and understand it is a not-borrow bit.
As with addition you can cascade this borrow. Think invert the carry in during a subtract with borrow if you implement that, dont just think of the carry in on a subtract as always being a 1. If I were to cascade the borrow I need to steal a 1 from the higher level subtraction, so instead of a carry in on subtract being a 1 always, I need to borrow that one to give to the lower ordered bits, so you carry in a 0 to facilitate that borrow. A subtract without borrow (a normal subtract) the normal carry in is a 0 for addition, for subtraction you invert that to make it a 1. For a subtract with borrow you take the borrow flag from the lower ordered subtraction and you invert that to make it the carry in. If there was no borrow then inverted it is a 1 if there was a borrow we borrow that 1 and carry in a 0
20 - 5 = 00010100 - 00000101
subtract
inverting the carry out we have borrow = 1
now a subtract with borrow we invert the borrow as our carry in.
so 20 - 5 = 0xF = 15, and we performed that with a subtract and then a subtract with borrow in the same way that with addition we would use add and then add with carry.
So for subtract invert the carry in, invert the second operand, and it is your choice architecturally to invert or not invert the carry out when done. Some architectures you see/touch every day invert, and others do not. If you dont invert and then have a subtract with borrow or a subtract with carry then you dont invert the carry bit you take it in as is.
Note that in this case neither one of these overflowed. Some architectures that have say 8 bit registers that can be combined as 16 bit registers (and so on) for an 8 bit add/subtract have one V flag but for the 16 bit alu there are two v flags one for the 8 bit part and one for the 16 bit part , a sort of half overflow just in case someone cared. This is again an architecturally specific design choice, in that case you would compare either bit 7 of the operands to bit 7 of the result or compare the carry in and carry out of bit 7 for the half overflow flag and bit 15 for the overflow flag.
As far as the term overflow, there is often a v flag to indicate overflow, in your brain when you read these terms think of the carry flag as "unsigned overflow" and the v flag as "signed overflow" (for addition and subtraction), you might say overflow in conversation but think signed overflow, even better SAY signed overflow in conversation for clarity and unsigned overflow when it makes sense to use that term.
Again this is for addition and subtraction. How the flags are used for multiplication and division is another exercise.
EDIT
If you wanted to do -70 + -80 = -150 then first off that is addition not subtraction so no inversions happen, the overflow is there though:
Two msbits are the same answer is different. carry in and carry out of the msbit differs so this is a signed overflow right answer is 0x16A but that cannot be represented in 8 bits so it is 0x6A with a signed overflow.
understand that the carry out DOES NOT just fall through to do -70 + -80 = -150 with 9 bit math you have to sign extend the operands one more bit.
its not 1+0+0 = 1 carry the 0 in that msbit it is 1+1+1 = 1 carry the 1, if you were to not sign extend then the carry out and carry in would not match for the msbit and you would have an overflow which would be incorrect.
If you were to do subtraction then I think it makes a difference to not put the full negative number for the second operand, invert (ones complement) and use the carry in for the plus one. Hmm maybe that does work let me think about it.
EDIT
Okay fair enough for all the bit patterns it still works. And that makes sense now that I see it. When implementing this in logic though you dont do the 2s complement on the second operand because that is an additional add operation, the inversion is simple, and the adding one by using the carry in is simple so I guess I always see it that way. if your professor wants it the other way then fine.
For the first example you dont drop the msbit down, that is off the end of the adder that is the carry out. you always discard the end carry with respect to the result. if there is an overflow (signed or unsigned) then the result is wrong as expected, if there is no overflow then the answer is right. that is the whole point of the overflow to tell you the answer is wrong
The first example the msbit of the first operand is a 1 the msbit of the second operand is a 0 it is not possible to have a signed overflow, the carry out is never part of the answer for fixed bit binary math. maybe you can also see why I show all the carry bits when I implement the math and never drop the carry out to the result, this is not grade school decimal math where we have an infinite number of digits/storage slots for the result.