1

In this article, it says the following:

1111 + 0001 = 0000 (carry flag is turned on)

As far as I know, a carry happens when the result does not fit in a certain number of bits (4 bits in this example), so the above equation indeed caused a carry (because the result is in effect 10000, which does not fit in 4 bits).


But look at the following from the same article:

0000 - 0001 = 1111 (carry flag is turned on)

I don't understand why the carry flag is set in this case, I mean the result is 1111, so it fits in 4 bits!

user8240761
  • 975
  • 1
  • 10
  • 15
  • 1111+0001=0000 translated to decimal is: (-1) + 1 = 0, the first bit is the carry flag, and the last three bits count from 0 to 7 (0000 to 0111) or from -8 to -1 (1000 to 1111). – johk95 Sep 01 '17 at 15:32
  • 3
    The carry flag on x86 indicates borrow when subtracting. – harold Sep 01 '17 at 15:48
  • Possible duplicate of [carry/overflow & subtraction in x86](https://stackoverflow.com/questions/8965923/carry-overflow-subtraction-in-x86) – Suma Sep 01 '17 at 16:20
  • Related (not duplicate, plus it's my answer): https://stackoverflow.com/questions/45261231/how-does-a-processor-without-an-overflow-flag-perform-signed-arithmetic/45261894#45261894, see discussion of carry flag towards the bottom – Cody Gray - on strike Sep 01 '17 at 16:25
  • this has been asked and answered many times now... – old_timer Sep 01 '17 at 17:23
  • the carry flag is the unsigned overflow not the signed overflow. – old_timer Sep 01 '17 at 17:29
  • @Suma: almost, but not quite a dup. That doesn't explain that CF means borrow after a subtraction. It just shows all the possible cases for CF and OF (and SF and ZF) with add and sub. You have to already understand how / why they're set for that to make sense. – Peter Cordes Sep 01 '17 at 18:11
  • See also [Understanding Carry vs. Overflow conditions/flags for signed vs. unsigned](http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt), and other links in [the x86 tag wiki](https://stackoverflow.com/tags/x86/info). – Peter Cordes Sep 01 '17 at 18:11

4 Answers4

2

If you disregard the size of the type, then

1111 + 0001 = 10000

That is why you get a carry (simply to indicate that the result is larger than the stored 0). This is important if you must add additional (hex) "digits".


With subtraction, you can get a similar problem:

0000 - 0001 = 1111

That actually says: 0 - 1 = 15. That is not true, so the carry is set to indicate that a borrow was performed, i.e. that, more or less, the following is performed:

10000 - 0001 = 1111 (16 - 1 = 15)

You do the same when you subtract in decimal:

    34
    18
  ---- -

To subtract 8 from 4, you must borrow 1 from the next digit, to get 14 − 8 = 6. That borrow is needed to get the subtraction of the next pair of higher digits right. 3 − 1 = 2, but you must subtract the borrow too, so now 3 − 1 − borrow = 1. That is why you (correctly) get 16 and not 26 as a result.

    34
    18
  ---- -
    16

The binary borrow has the same function: it is stored in the carry flag and can be subtracted (e.g. in x86 assembler), using SBB (subtract with borrow) instead of a plain SUB (subtract). The value of the carry flag (which is functioning as a "borrow flag" now) is additionally subtracted from the two operands:

Value1  DW      0x1234  ; alternatively: DB 0x34,0x12
Value2  DW      0x0678  ;                DB 0x78,0x06  
Result  DW      0

        MOV     AL,BYTE PTR [Value1]      ; 0011 0100
        SUB     AL,BYTE PTR [Value2]      ; 0111 1000
        MOV     BYTE PTR [Result],AL      ; 0xBC = 1011 1100, but a borrow was needed!
        MOV     AL,BYTE PTR [Value1 + 1]  ; 0001 0010
        SBB     AL,BYTE PTR [Value2 + 1]  ; 0000 0110 (0x12 - 0x06 - carry = 0x0B)
        MOV     BYTE PTR [Result + 1],AL  ; 0x0B = 0000 1011 
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • But isn't subtraction in x86 is done using addition (we invert the second number and add one to it, and then we add the two numbers)? – user8240761 Sep 02 '17 at 08:19
  • 1
    @user8240761: Huh? Where did you get that idea? Subtraction is simply done through subtraction. Ok, how this is done internally, in the CPU, (if there is extra subtraction hardware or just adder hardware that gets negated data) I don't know, but for us users of the CPU, it is a real subtraction, with a borrow. So what I wrote applies. – Rudy Velthuis Sep 02 '17 at 11:29
  • I have read in many places that one of the reasons why two's complement was chosen to represent integers in a computer is that you can do both addition and subtraction using the same logic (by adding). – user8240761 Sep 02 '17 at 11:31
  • OK I think I got it, like you said as programmers we shouldn't think about how subtraction is done inside the CPU, we should simply assume that subtraction is done like we do it in "real life" (by subtracting and not by adding!). So the carry flag will be set if when we are doing the subtraction, we needed to borrow, correct? – user8240761 Sep 02 '17 at 11:37
  • As I said, how this is done internally doesn't matter. This question has an x86 tag, so I refer to the x86 range of processors, and to us users of the CPU, the results are as if a pure subtraction is done. But it is true that -A = ~A + 1, so inverting the second operand and then adding it plus one will give the same result. But again, for us, users of an x86 CPU, that shouldn't matter. – Rudy Velthuis Sep 02 '17 at 11:38
  • Yes. That is why SBB is called that way, i.e. "Subtract with borrow". – Rudy Velthuis Sep 02 '17 at 11:41
  • One last question if you don't mind, maybe I forgot how this is done, but when we borrow, shouldn't there be a number that we can borrow from? I mean in your decimal subtraction example, you borrowed from the number **3**, but from where did you borrow in your binary subtraction example? – user8240761 Sep 02 '17 at 11:41
  • @user8240761: Yes, in real life, there should be a number we can borrow from. But when processing multiple digits or numbers of a larger number, we don't know them yet, so we simply remember (i.e. set the carry flag) there is a borrow. If there is a next digit, you use SBB, otherwise it is up to you how to handle a set carry (borrow) at the end of your routine. My multiple precision code always subtracts the smaller from the larger number, to avoid that problem. This means it must compare often large numbers first, quite some overhead, but there is no other good way to handle a stray borrow. – Rudy Velthuis Sep 02 '17 at 11:49
2

On most CPUs (including x86 CPUs) the carry flag behaves the following way for both addition and subtraction:

The carry flag is the highest bit of the result when extending the "length" of the numbers by one bit.

Example:

 1110 +  0011 = 01110 + 00010 (extending 4 bits to 5 bits)
01110 + 00011 = 10001 (5 bit result)
 1110 +  0011 =  0001, Carry=1 (highest of the 5 bits is the carry flag)

 0010 -  0011 = 00010 - 00010 (extending 4 bits to 5 bits)
00010 - 00011 = 11111 (5 bit result)
 0010 -  0011  = 1111, Carry=1 (highest of the 5 bits is the carry flag)

(However there are CPUs where the carry flag bahaves differently on subtractions; Example: the historic 6502)

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
1

we know from grade school that a - b = a + (-b) and we know that using twos complement to negate something means invert and add one. and some know that processors dont subtract they add instead so

  0000
 -0001
=======

is really

      1
   0000
+  1110
========

invert and add one, since we have to carry in anyway we add the one there rather than do extra work. so we invert the carry in and we invert the second operand on the way into the adder.

  00001
   0000
+  1110
========
   1111

And you are correct that is the answer but some processors invert the carry out, and it sounds like the one you are using does that. Why? Because if you examine some other sets of numbers you see that the bit can be used as a borrow or not borrow bit rather than an unsigned overflow which is what it means for unsigned numbers, as in this case. 0000 + 1111 = 1111 which is not an unsigned overflow.

So from one architecture to the next (ARM, MIPS, AVR, x86, etc) if you want to use that flag (well not MIPS) you read the documentation, or do an experiment as the docs are not that good on this topic. Sometimes the add with carry or subtract with borrow instructions will hint at which way that architecture works (inverts the carry flag on the way out of a subtract).

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • Great answer, very good to point out that not all ISAs are the same for this. I found Intel's x86 documentation that describes it: [`SBB` (sub with borrow)](http://felixcloutier.com/x86/SBB.html) manual says the input value of CF is used as a borrow input: `DEST ← (DEST – (SRC + CF));`. It also says: *the processor evaluates the result for both data types and sets the OF and CF flags to indicate a borrow in the signed or unsigned result, respectively.* – Peter Cordes Sep 01 '17 at 18:21
0

So you said that this equation...

0000 - 0001 = 1111 (carry flag is on)

... set Carry flag on?

Yes, it will because when Addition is performed Carry will set when data is overflowed! In case of Subtraction operation Carry flag is Borrow flag.

As you can see in Intels 8085 Programming Guide, Subtraction complements the carry flag!

How "SBB" works explained in Intel's 8085 Programming Guide!

That equation generates no carry, but Complemented by Subtraction! Hope it helps!