Binary to fraction conversion is the mathematical process of translating a base-2 number with a radix point into a base-10 decimal or common fraction by summing the negative powers of two for each bit position right of the point. When you are programming an ESP32 to read an analog sensor, configuring a digital-to-analog converter (DAC) for audio synthesis, or writing digital signal processing (DSP) algorithms, the microcontroller does not natively "see" 3.3 volts or a musical waveform. It sees a stream of 1s and 0s. Understanding how those binary bits map to fractional real-world voltages is the critical bridge between abstract code and physical circuit behavior.

The Core Math: Converting Binary to Fraction

In standard integer binary, each bit position moving left from the least significant bit (LSB) represents a positive power of two ($2^0, 2^1, 2^2$, etc.). When we introduce a radix point (the binary equivalent of a decimal point), the bit positions to the right of the point represent negative powers of two.

The positional weights to the right of the 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$
The Golden Rule of Binary Fractions: Just as moving left of the decimal in base-10 multiplies by 10, moving right of the radix point in base-2 divides by 2. A binary fraction can only exactly represent decimals that are sums of inverse powers of two. Numbers like 0.1 (one-tenth) result in infinitely repeating binary fractions, which is a primary source of precision loss in embedded math.

Worked Numeric Example

Let us convert the binary fraction 0.1011 into a base-10 decimal and a common fraction.

Bit PositionBit ValueWeight ($2^{-n}$)CalculationDecimal Result
-110.5$1 \times 0.5$0.5000
-200.25$0 \times 0.25$0.0000
-310.125$1 \times 0.125$0.1250
-410.0625$1 \times 0.0625$0.0625

Summing the results: $0.5 + 0 + 0.125 + 0.0625 = 0.6875$.
Expressed as a common fraction, since the lowest denominator is $2^4 = 16$, the numerator is $8 + 0 + 2 + 1 = 11$. Therefore, 0.1011 in binary is exactly 11/16 in base-10.

Where You Meet This in Practice

What this changes in a real circuit is how you scale, interpret, and generate physical voltages using digital logic. You encounter binary fractions primarily in three embedded scenarios:

  1. ADC Scaling and Normalization: When a 12-bit ADC on an ESP32 reads a sensor, it returns an integer between 0 and 4095. To use this in a control loop (like a PID controller), you often normalize it to a binary fraction between 0.0 and 1.0. Dividing by 4095 using standard floating-point math is slow on 8-bit or 32-bit cores without hardware floating-point units (FPUs). Instead, engineers use fixed-point binary fractions to shift and mask bits.
  2. DAC Waveform Generation: If you are synthesizing a sine wave on a DAC, the lookup table values are often stored as fractional binary representations of the peak voltage. A 16-bit signed audio sample ranges from -32768 to +32767, where each integer step represents a fractional voltage increment of exactly 1/32768 of the full-scale range.
  3. Digital Filters (FIR/IIR): In audio DSP, filter coefficients are rarely clean decimals. They are stored in Q-format (e.g., Q15), which is a standardized way of treating a 16-bit integer register as a binary fraction where the radix point is implicitly fixed just after the sign bit.

For a deeper look at how analog signals are quantized into these digital steps, review SparkFun's Analog to Digital Conversion Guide, which details the hardware reality behind the math.

Fixed-Point vs. Floating-Point: The Common Confusion

What people most commonly confuse binary fractions with is IEEE 754 floating-point representation. When a hobbyist sees a fractional number in C++ code (e.g., float voltage = 0.6875;), they assume the microcontroller is storing it exactly like a base-10 fraction. It is not.

Floating-point uses a complex arrangement of sign bits, exponents, and mantissas to allow the radix point to "float," accommodating incredibly large and incredibly small numbers at the cost of processing overhead. Binary fractions (used in fixed-point arithmetic) lock the radix point in a specific, predefined location within the register. For a comprehensive breakdown of processor-level math, the All About Circuits Digital Logic Textbook provides excellent foundational schematics.

CriteriaBinary Fractions (Fixed-Point)IEEE 754 (Floating-Point)
Radix PointFixed implicitly by the programmer (e.g., Q15 format)Floats dynamically based on the exponent field
Hardware RequirementStandard Integer ALU (shifts and adds)Requires dedicated FPU silicon or heavy software emulation
Execution SpeedExtremely fast (1-2 clock cycles on most MCUs)Slow on MCUs without FPU (dozens of cycles)
Precision BehaviorUniform absolute precision across the rangeUniform relative precision (more resolution near zero)
Best Use CaseAudio DSP, motor control loops, PID scalingScientific calculations, GPS coordinates, complex physics

If you are programming an Arduino Uno (ATmega328P) or an ESP8266, neither has a hardware FPU. Using float triggers software emulation, which can bottleneck a high-speed interrupt service routine (ISR). Converting your math to binary fractions (fixed-point) using 32-bit integers (int32_t) will drastically reduce ISR execution time.

FAQ: Binary to Fraction Conversion Questions

How do you convert a repeating binary fraction to a decimal?

Just as $0.333...$ in base-10 equals $1/3$, certain fractions repeat infinitely in base-2. For example, the base-10 fraction $1/3$ in binary is $0.010101...$ (repeating 01). To convert a repeating binary fraction mathematically, you use the geometric series sum formula. If the repeating block is 01 (which is $1$ in base-2, shifted by 2 bits), the value is $1 / (2^2 - 1) = 1/3$. In embedded systems, you never store infinite repeats; you truncate the binary fraction to the bit-width of your register (e.g., 16 or 32 bits), which introduces a quantization error that you must account for in your noise floor calculations.

Why do microcontrollers use binary fractions instead of standard decimals?

Microcontrollers use binary fractions (fixed-point math) because their fundamental hardware architecture—the Arithmetic Logic Unit (ALU)—is physically wired to perform integer addition, subtraction, and bit-shifting. Standard base-10 decimals do not map cleanly to silicon logic gates. By treating an integer register as a binary fraction, programmers can execute fractional multiplication and division using simple, ultra-fast bit-shift operations (e.g., shifting right by 4 bits is mathematically identical to dividing by 16, or $2^4$), bypassing the need for power-hungry and silicon-heavy floating-point units.

How do I convert a mixed binary number (integer and fraction) to a decimal?

Split the number at the radix point and process each half independently. Take the binary number 101.11.
1. Integer part (101): $(1 \times 2^2) + (0 \times 2^1) + (1 \times 2^0) = 4 + 0 + 1 = 5$.
2. Fractional part (.11): $(1 \times 2^{-1}) + (1 \times 2^{-2}) = 0.5 + 0.25 = 0.75$.
3. Combine: $5 + 0.75 = 5.75$.
This exact method is how you decode raw serial data packets from sensors that transmit mixed-format telemetry.

What is the maximum precision of a binary fraction in a 32-bit register?

If you dedicate all 32 bits of an unsigned register to the fractional part (a format sometimes called Q0.32), the radix point sits to the left of the most significant bit. The smallest possible non-zero value is the LSB, which represents $2^{-32}$. In base-10, $2^{-32}$ is approximately 0.0000000002328306. This gives you roughly 9.6 decimal digits of precision. However, if you are using a signed 32-bit register (Q31 format) to allow for negative fractional values, one bit is consumed by the sign, leaving 31 bits for the fraction, making the maximum precision $2^{-31}$ (approx. $0.00000000046566$).