Binary subtraction is the mathematical process of deducting one base-2 number from another using specific bitwise borrowing rules or, more commonly in modern hardware, two's complement addition. When you write int x = a - b; on an ESP32 or Arduino, the microcontroller doesn't actually 'subtract' in the way you learned in grade school; it manipulates logic gates to add a negative. Understanding the rules of binary subtraction is critical for debugging integer underflow, optimizing DSP algorithms, and designing custom FPGA logic.

The Core Rules of Binary Subtraction (Base-2 Borrowing)

At the most fundamental level, base-2 borrowing follows a strict truth table. If you are designing a dedicated half-subtractor or full-subtractor circuit out of discrete 7400-series logic gates, these are the exact rules your silicon must execute.

Minuend (A) Subtrahend (B) Difference (D) Borrow Out (Bout)
0000
1010
1100
0111

Worked Numeric Example: Standard Borrowing

Let's subtract 6 from 13. In decimal, this is 13 - 6 = 7. In binary, 13 is 1101 and 6 is 0110.

  • Bit 0 (1s place): 1 - 0 = 1. (No borrow)
  • Bit 1 (2s place): 0 - 1. We must borrow from Bit 2. Bit 1 becomes 2 (in decimal concept), so 2 - 1 = 1. (Borrow generated)
  • Bit 2 (4s place): The original 1 was borrowed from, leaving 0. We need to calculate 0 - 1. We borrow from Bit 3. 2 - 1 = 1. (Borrow generated)
  • Bit 3 (8s place): The original 1 was borrowed from, leaving 0. 0 - 0 = 0.

The result is 0111, which is exactly 7 in decimal. While this makes sense on paper, building a cascading borrow chain in hardware creates severe propagation delay. This leads us to how modern silicon actually handles the math.

What People Commonly Confuse: Borrowing vs. Two's Complement

The most common mistake hobbyists and junior firmware engineers make is assuming the CPU uses the borrowing method shown above. In reality, almost all modern Arithmetic Logic Units (ALUs) use two's complement addition to perform subtraction.

The Odometer Analogy: Think of two's complement like a mechanical car odometer rolling backward. If you are at 000000 and roll back one mile, the odometer doesn't show a negative sign; it rolls over to 999999. In an 8-bit binary system, rolling back from 00000000 yields 11111111, which the ALU interprets as -1.

To subtract B from A using two's complement, the hardware does three things:

  1. Inverts all bits of B (using simple NOT gates).
  2. Adds 1 to the inverted B (by asserting the Carry-In pin on the adder).
  3. Adds this modified B to A using a standard binary adder.

Worked Example (13 - 6 via Two's Complement):
A = 1101 (13)
B = 0110 (6)
Invert B: 1001
Add 1 to inverted B: 1010 (This is the two's complement representation of -6).
Add A + (-B): 1101 + 1010 = 10111.
Discarding the 5th carry-out bit leaves 0111 (7). No complex borrow-routing required.

Where You Meet This in Practice: ALUs and Microcontrollers

Understanding these rules changes how you evaluate hardware architecture and write bare-metal code. In a real circuit, using two's complement instead of a dedicated subtractor drastically reduces the silicon area and gate count. According to the Espressif ESP32 Technical Reference Manual, the Xtensa LX6 ALU relies on shared adder circuitry for both addition and subtraction, toggling a single control line to invert the B-input bits and set the carry-in high.

A dedicated 32-bit binary subtractor requires roughly 30% more logic gates and suffers from longer propagation delays than a 32-bit adder configured for two's complement subtraction.

When you are programming FPGAs in Verilog or VHDL, you can explicitly instantiate a full-subtractor, but synthesis tools like Xilinx Vivado or Intel Quartus will almost always optimize assign diff = a - b; into an adder with inverted inputs. If you are studying digital logic from the ground up, the Nand2Tetris project provides an excellent framework for building an ALU that switches between addition and subtraction using a single XOR gate array and a control bit.

Debugging Binary Math Errors in Embedded C/C++

Because microcontrollers execute binary subtraction strictly by the bits, ignoring human concepts of 'negative' unless explicitly told otherwise, math errors frequently destroy hardware or crash firmware.

The Unsigned Underflow Hazard

If you subtract a larger number from a smaller number using an unsigned integer type, the ALU doesn't throw an error. It simply wraps around.

uint8_t position_target = 5;
uint8_t position_current = 10;
uint8_t error = position_target - position_current; 
// error is NOT -5. It is 251.
Safety Warning for Motor Control: If you use unsigned integers for PID error calculations in a BLDC motor controller or a drone flight stack, an underflow resulting in 251 (instead of -5) will command the PWM duty cycle to near 100%. This can instantly overheat and destroy your driver MOSFETs or cause a physical crash. Always use signed integers (int8_t, int16_t) for any variable that represents a difference or error margin.

For deeper insights into how these bitwise operations map to C/C++ data types, the All About Circuits digital logic textbook offers comprehensive chapters on binary arithmetic and hardware mapping.

Frequently Asked Questions

What are the rules for binary subtraction with negative numbers?

In standard hardware, negative numbers don't have a separate subtraction rule; they are already stored in two's complement format. To subtract a negative number (e.g., A - (-B)), the ALU takes the two's complement of the already-negative B (which turns it back into a positive B) and adds it to A. Essentially, subtracting a negative number becomes standard binary addition.

How do you subtract binary numbers with different lengths?

Before subtraction, the shorter binary number must be padded with leading zeros to match the bit-width of the longer number. For example, if subtracting 101 (5) from 11010 (26), you pad the subtrahend to 00101. If you are using signed numbers, you must use 'sign extension' instead of zero-padding—copying the most significant bit (the sign bit) into the new leading positions to preserve the negative value.

Why do computers use two's complement instead of standard binary subtraction rules?

Computers use two's complement because it allows the ALU to use the exact same physical adder circuitry for both addition and subtraction, saving millions of transistors and reducing propagation delay. Furthermore, two's complement ensures there is only one representation for zero (00000000), whereas older systems like 'one's complement' or 'sign-magnitude' suffered from having both a positive zero and a negative zero, which complicated logic branching and equality checks.

How does a full subtractor circuit work in digital logic?

A full subtractor is a combinational logic circuit that performs subtraction on three bits: the Minuend (A), the Subtrahend (B), and a Borrow-In (Bin) from a previous less-significant stage. It produces two outputs: the Difference (D) and the Borrow-Out (Bout). The Difference is calculated using two cascaded XOR gates (A XOR B XOR Bin), while the Borrow-Out is generated using a combination of AND, OR, and NOT gates to detect if A is smaller than the combined value of B and Bin.