Binary fractions are the portion of a base-2 number to the right of the radix point, representing fractional values less than one using descending negative powers of two. If you are programming microcontrollers, reading sensors, or driving analog outputs, this mathematical concept is the invisible grid that dictates the exact voltage step size—or Least Significant Bit (LSB)—your hardware can resolve. Understanding binary fractions changes how you debug noisy sensor readings, design precision control loops, and select the right digital-to-analog converter (DAC) for your bench projects.

The Core Concept: What Are Binary Fractions?

In the decimal system, numbers to the right of the decimal point represent tenths, hundredths, and thousandths ($10^{-1}, 10^{-2}, 10^{-3}$). In binary, the radix point (the binary equivalent of a decimal point) separates the integer from the fractional part, but the columns represent halves, quarters, eighths, and so on ($2^{-1}, 2^{-2}, 2^{-3}$).

The positional weights to the right of the binary radix point are:

  • First bit: $2^{-1} = 0.5$
  • Second bit: $2^{-2} = 0.25$
  • Third bit: $2^{-3} = 0.125$
  • Fourth bit: $2^{-4} = 0.0625$

By the time you reach a 10-bit fractional resolution ($2^{-10}$), the step size is exactly 0.0009765625. This rapid shrinking of step sizes is why high-bit ADCs are required for precision measurement, but it also introduces the "repeating fraction" trap.

The 0.1 Decimal Trap: Not all decimal fractions can be represented exactly in binary. Just as 1/3 becomes a repeating decimal (0.333...) in base-10, the decimal value 0.1 becomes a repeating binary fraction (0.0001100110011...). If you try to store 0.1 in a fixed-length binary register, it will always be slightly truncated, leading to cumulative rounding errors in financial or high-precision timing code.

Worked Numeric Example: Converting Decimal to Binary

Let’s convert the decimal fraction 0.8125 into a binary fraction using the multiply-by-2 method. This is the exact algorithm running in the background of your microcontroller's math library when mapping analog values.

  1. Multiply by 2: $0.8125 \times 2 = 1.625$. The integer part is 1. Keep the fractional part (0.625).
  2. Multiply by 2: $0.625 \times 2 = 1.25$. The integer part is 1. Keep the fractional part (0.25).
  3. Multiply by 2: $0.25 \times 2 = 0.50$. The integer part is 0. Keep the fractional part (0.5).
  4. Multiply by 2: $0.50 \times 2 = 1.00$. The integer part is 1. The fractional part is 0, so we stop.

Reading the integer parts from top to bottom, the binary fraction is 0.1101.

Verification: Let's map it back to decimal using the negative powers of two.
$1(2^{-1}) + 1(2^{-2}) + 0(2^{-3}) + 1(2^{-4})$
$= 0.5 + 0.25 + 0 + 0.0625$
$= 0.8125$. The math holds up perfectly on the bench.

Where You Meet Binary Fractions in Practice

You interact with binary fractions every time an analog signal crosses the boundary into digital logic. Here is where they physically manifest in your circuits:

  • Analog-to-Digital Converters (ADCs): A standard Arduino Uno uses the ATmega328P’s 10-bit ADC. With a 5V reference, the binary fraction grid divides 5V into $2^{10}$ (1024) steps. The LSB voltage is $5V / 1024 = 4.88mV$. If your sensor outputs 4.80mV, the ADC cannot resolve it; it will read as 0 or 1.
  • PWM Duty Cycles: When you use analogWrite() or the ESP32’s LEDC peripheral, the duty cycle is a binary fraction of the period. An 8-bit PWM resolution gives you 256 discrete steps (0 to 255), meaning you can only set duty cycles in increments of roughly 0.39%.
  • Digital-to-Analog Converters (DACs): External DACs like the Microchip MCP4725 use I2C to receive a binary integer, which the internal resistor ladder translates into a voltage using binary fraction weighting.

Real-World Scenario: The 12-Bit DAC Quantization Trap

The Setup: You are building a programmable power supply using an ESP32 DevKit v1 and an external 12-bit MCP4725 DAC on an I2C bus. Your DAC is tied to a precise 3.3V voltage reference. Your goal is to output exactly 1.250V to bias a transistor gate.

The Numbers: A 12-bit DAC has $2^{12} = 4096$ discrete steps.
The LSB step size is $3.3V / 4096 = 0.000805664V$.
To find the required digital register value, you divide your target voltage by the step size:
$1.250V / 0.000805664V = 1551.513$.

The Outcome: Microcontrollers cannot send half-steps to a DAC. The integer truncates to 1551. The actual output voltage becomes $1551 \times 0.000805664V = 1.24958V$.

What Went Wrong: You have a quantization error of roughly 0.42mV. In a simple LED dimming circuit, 0.42mV is invisible. But if this 1.250V signal feeds into a high-gain op-amp stage (say, 100x gain for a current shunt monitor), that 0.42mV binary fraction truncation error becomes a 42mV offset at the output, completely throwing off your ESP32's feedback loop.

The Fix: You cannot fix the math of a 12-bit binary fraction grid. To achieve exactly 1.250V (or get close enough that the error is negligible), you must upgrade to a 16-bit DAC like the DAC8562. A 16-bit grid over 3.3V yields an LSB of $50\mu V$, dropping your quantization error to virtually zero for standard bench applications.

Common Confusions: Fixed-Point vs. IEEE 754 Floating-Point

The most frequent mistake hobbyists make is confusing raw binary fractions (fixed-point math) with floating-point representation. When you type float voltage = 1.25; in Arduino C++, you are not using a simple binary fraction; you are using the IEEE 754 standard.

Feature Fixed-Point Binary Fraction IEEE 754 Floating-Point (32-bit)
Radix Point Static (fixed in hardware or software scaling) Dynamic (moves based on the exponent)
Hardware Cost Low (simple add/shift logic) High (requires FPU or heavy software emulation)
Precision Uniform across the entire range Decreases as numbers get larger
Common Use Case DAC registers, ADC raw reads, PWM timers PID control loops, complex sensor math

When writing firmware for an 8-bit AVR (like the ATmega328P), floating-point math is emulated in software and eats up clock cycles and flash memory. Seasoned firmware writers often scale their math to use fixed-point binary fractions (e.g., representing 1.25V as the integer 1250, or using Q-format fractional math) to keep the execution time deterministic.

Frequently Asked Questions

Why does my Arduino analogRead() fluctuate by 1 or 2 bits even when the input is tied to a stable battery?
This is rarely a failure of binary fraction math; it is physical noise. A 10-bit ADC resolving 5V has an LSB of 4.88mV. If your breadboard has 10mV of ground bounce or thermal noise on the rail, the ADC will naturally toggle between two adjacent binary fraction steps (e.g., 512 and 513). Implement a software moving-average filter to smooth the binary output.

Can I output an exact 0.1V step using an 8-bit DAC on a 5V rail?
No. An 8-bit DAC on a 5V rail has an LSB of $5V / 256 = 19.53mV$. The closest steps to 0.100V are $5 \times 19.53mV = 97.65mV$ and $6 \times 19.53mV = 117.18mV$. To get exact 100mV steps, your DAC's LSB must be a clean divisor of 0.1, which requires a specific voltage reference or a higher bit-depth converter.