Subtraction using hexadecimal numbers?

0x0E - 0xFF gives you a +15 in signed decimal integer but can you show me the steps to subtract in hex. It requires you to carry from the right, maybe I'm wrong.

oyubir2021-03-11T10:01:10Z

Favorite Answer

0x0E - 0xFF is NOT +15.
It is -241.

Do not confuse two, completely unrelated, problems.
* Hexadecimal
* Representation of negative number.

Claiming 0x0E-0xFF=+15 is exactly (really exactly) the same thing as saying "14-255=15".

The only reason why people don't see how obviously false it is when using hexa, and see it when using decimal, is just because we do a mental confusion with "hexa -> low level" and "low level -> -15 and 241 has the same 8 bit representation".


So In hexa substraction is done exactly like in decimal
 0x0E
-0xFF
--------
FF is bigger than 0E, so do the reverse subtraction and add a minus sign
FF-0E
F-E=1, no carry. Last digit of result is 1.
F-0=F, no carry. First digit is F.
No other computation

So 0x0E-0xFF = -0xF1

A more complex example
 0x2A5
-0x18B
----------
5-B = -6, which is negative. So add 10 (0x10) and carry 1. Last digit is 0x5-0xB+0x10 = 0xA
A-8-1 (-1 because of previous carry) is 1.
2-1=1

So 3 digits of the result are 11A

========================

So subtraction in hexa is just a subtraction, like in all other bases. a-b is -(b-a) (which is how you compute it if b is bigger than a). a - (-b) is a+b. Etc.
And to compute it by hand, you just perform digit per digit subtraction from right to left, sometimes carrying a 1.
Exactly like you do in base 10.


A completely unrelated matter is the fact that, on a computer, with limited bits to represent integers, you can represent only a given different numbers.
On 8 bits, you can represent only 256 different values.
There are different choices of mapping between the 256 possible combination of eight 0 or 1, and 256 integers values.
The most commons are the unsigned binary one (00000000 -> 0, 00000001 -> 1, ..., 01111111 -> 127, 10000000 -> 128, 10000001 -> 129, ...,  11111110 -> 254, 11111111 -> 255)
and the signed one
(00000000 -> 0, 00000001 -> 1, ..., 01111111 -> 127, 10000000 -> -128, 10000001 -> -127, ..., 11111110 -> -2, 11111111 -> -1)

Advantage of that signed representation is that, for lot of operations, it is transparent for the processor. Processor doesn't need to know whether a packet of 8 bits represent a signed or unsigned value to perform the operation. Result will be the same, and interpretation is up to the user.
10000001 + 00000001 = 10000010 whatever.
It is up to you to interpret that as meaning
129 + 1 = 130
or meaning
-127 + 1 = -126.
Both are true anyway, but from an electronic point of view, it is the same 10000001+00000001=10000010 computation)

But that leads to the fact that 129 and -127 have the same representation (depending on whether you choose to interpret 10000001 as signed or unsigned).
130 and -126 also.
And, in your case, 1 and 255 also. -241 and +15 also.

That is true even in hexa.
0xFF and 0x01 have the same 8 bits representation. So do -0xF1 and 0x0F.

The only reason why you are most used to see it in hexa, is because of a coincidence : the cases when you may want to say "-0xF1 and 0x0F have the same 8 bits representation" happens to be the same as those when you may want to use hexadecimal : when you are interested in memory content of a computer, bytes by bytes.
In an algebra lesson you would never bother to talk about 8 bits representation of numbers. Nor would you use hexadecimal basis.

But that is just a coincidence. Hexa is the basis we most often use to talk about bytes values. And talking about 8 bits representation of numbers is talking about bytes values.


So, bottom line.
14-255 = 0x0E-0xFF = -0xF1 = -241

And, yes, 255 happens to have the same 8 bits representation as -1. -241 the same 8 bits representation as 15.
So, that arithmetic operation is the same for a CPU as
14-(-1) = 0x0E-(-0x01) = 0x0F = 15


Note that you have to choose, tho.
You can't choose to interpret half of the 8 bits numbers as signed one, and the other as unsigned one. Or else you are doomed to say silly things such as
14-255 = +15
(or, 0x0E-0xFF=0x0F)

Richard2021-03-12T22:32:55Z

Unsigned hexadecimal single byte numbers go from

0x00 to 0xFF representing 0 to 255 in decimal.

As signed numbers

0x80 to 0xFF representing -128 to -1 and
0x00 to 0x7F representing 0 to 127.

As signed numbers:

0x0E - 0xFF = 14 - (-1) = 14 + 1 = 15

As unsigned single byte numbers

0x0E - 0xFF = 14 - 255 = -241

however, the question says 'signed decimal integer' and -241 is out of the range. So

-241 + 256 = 15

256 is the total range of values for an 8 bit byte.

if we take the two numbers as 16 bit values

0x000E - 0x00FF = 0x000E + 0xFF01 = 0xFF0F or
0x000E - 0xFFFF = 0x000E + 0x0001 = 0x000F

In either case, take the least significant 8 bits the result is

0x0F = 15 in decimal.

husoski2021-03-11T16:34:25Z

In decimal, +15 is just 15.  The important question is, "Are 0x0E and 0xFF to be considered signed (8-bit) numbers or not?"

If they're signed, and if the representation is twos complement, then that's equivalent to the decimal operation 14 - (-1), and the result is 15 (0x0F) with no overflow.

If you want to do that operation in twos complement, using hexadecimal notation, there are two easy ways.  First is to just do unsigned hexadecimal subtraction, appending a leading 1 to the first number if it's too small.

    0x0E - 0xFF  ...becomes...   0x10E - 0xFF, and then:

          1 0 E
        -    F F
         --------
             0 F

    You borrowed 1 from the left to make E into 1E and then 1E - F = F is the
    rightmost place.  Propagating that borrow to the left means you had 0-1 on
    top in the second place.  Borrow again to get 10-1 - F on top, and then
    F - F = 0 in the second result place.  Don't bother with the third (leftmost)
    place.

That's pretty easy once you get used to multi-step borrowing (just like in decimal where 1001 - 13 requires three borrows to get the rightmost digit); but the second easy way is even easier.  Just complement and add:

    0x0E - 0xFF  ...becomes... 0x0E + 0x01

...and the answer 0x0F is immediately obvious in this case.

For more complex cases, that idea is still pretty nice.  With oyubir's example:

  0x2A5 - 0x18B  ...becomes... 0x2A5 + 0xE75
  5 + 5 = A
  A + 7 = 1, carry 1
  2 + E + 1 = 1, carry 1
  Ignore the final carry and the answer is 0x11A, using only addition facts.

Daniel H2021-03-11T16:10:15Z

The answer is 0x0F = 15 not -241 like you would think.
If you keep it 1 byte (0x00 to 0xFF)

The question is do you understand why?
1st is that 1byte numbers have a range of 256 values (0 to 255). What if we wanted positive and negative numbers? Then we sacrifice the 1st bit for the sign then the range is -128 to 127.

There is no way to represent -241 with 1 byte or any hex value from 0x00 to 0xFF

You have to go larger, but the answer changes depending on how large you go.
2 bytes: 0x0000 to 0xFFFF
0x0E - 0xFF = 0xFF0F

4byte: 0x00000000 to 0xFFFFFFFF
0x0E - 0xFF = 0xFFFFFF0F

2nd: DO NOT DO SUBTRACTION. Instead flip the sign and add

decimal example:
5 - 4 is the same as 5 + (-4)
Instead of subtracting, we are adding the "negative"

How to convert hex or binary to "negative"
We'll do 2-byte example for this
0x00FF 

1st flip the bites (0 becomes 1, 1 becomes 0)
0xFF00
2nd add 1
0xFF01

0xFF01 is the "negative" of 0x00FF

Now you can add the two

0x0E + 0xFF01 = 0xFF0F

Tasm2021-03-11T07:49:41Z

The way I would do it is to enter it into a scientific calculator freely available online, even windows has a free calculator to hex.