I'm sure it's obvious as day, but i'm having a hard time convincing myself with all these carries and conversions...

Given that i'm operating on the same number (say, 0xA451) in different representations(0x and 0b), is it always safe to use "16's complement" (not an actual term) to represent the opposite number instead of "going down" to binary and using two's complement?

I.e. I want to know what minus 0xA451 is so i do (0xFFFF - 0xA451) + 0x0001 = 0x5baf. Else, i could have done 0xA451 = 1010 0100 0101 0001, flip them bits and add one:

0101 1011 1010 1110 +
0000 0000 0000 0001 =
0101 1011 1011 0000, which is indeed 0x5baf.
I would appreciate somebody confirming that this is always true.

  • 1
    \$\begingroup\$ Consider using Excel or a tool to check every possible outcome? \$\endgroup\$ – MadHatter Jan 13 at 4:04
  • 1
    \$\begingroup\$ I'd say especially in 0b, 0o and 0x its obvious .. you only traverse the number bit by bit in the first case - and in groups of 3 bits for the octal and 4 bits in hexadecimal case - which IS OBVIOUSLY not changing the result. \$\endgroup\$ – eagle275 Jan 13 at 12:12

You can use whatever base you want, as long as you use the same limit to your number range. For example, here's how 16-bit two's complement would work with decimal numbers:

2s_comp  =  0b10000000000000000 - number  =  0x10000 - number  =  65536 - number

Number   Decimal  2s_Comp_Hex 2s_Comp_Dec
0xA451   42065    5BAF        23471
0xE227   57895    1DD9        7641

The method where you invert each bit and add one works for numbers of any length, but mathematically, this is what's going on -- the range of your numbers is limited, and you're doing addition modulo that range.

To subtract the first number (0xA451) from the second (0xE227):

(0xE227 + 0x5BAF) % 0x10000  =  0x3DD6  =  0xE227 - 0xA451
(57895 + 23471) % 65536  =  15830  =  57895 - 42065

You can see from converting hex to decimal that this is exactly the same calculation. The same thing happens with binary vs. hexadecimal.

Computers work in binary, so they use two's complement, but you can use the complement of any base. Here's an example showing three-digit ten's complement in both decimal and hexadecimal:

10s_comp  =  1000 - number  =  0x3E8 - number

Number   Hex     10s_Comp_Dec  10s_Comp_Hex
284      0x11C   716           0x2CC
635      0x27B   365           0x16D

(635 + 716) % 1000  =  351  =  635 - 284
(0x27B + 0x2CC) % 0x3E8  =  0x15F  =  0x27B - 0x11C

What you're doing is still safe, since you're still performing twos-complement operations on a signed integer, just with hex representations of the integer shown as you perform operations.

(0xFFFF - 0xA451) is the same thing as (0b1111_1111_1111_1111 - 0b1010_0100_0101_0001) which is just flipping the bits. Next, adding 0x1 modulo 0x10000 is the same as adding binary 1 modulo 0b1_0000_0000_0000_0000, since addition is an inherent property of the numbers rather than their representations in a particular base.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.