Fractional decimal to binary conversion is the mathematical process of translating a base-10 number less than one into a base-2 sequence by repeatedly multiplying the fractional part by two and recording the integer carry bits. In a real circuit, this math dictates the exact register value you write to a microcontroller's DAC or PWM peripheral to achieve a specific analog voltage or duty cycle, directly impacting signal fidelity and control loop precision. Most beginners confuse this raw fixed-point binary fraction with IEEE 754 floating-point representation, not realizing that hardware registers don't natively understand floating-point decimals without heavy CPU overhead.
The Core Algorithm: Multiplying by Two
To convert a fractional decimal to binary, you isolate the fractional part and multiply it by 2. The integer part of the result (which will always be 0 or 1) becomes your next binary bit, reading from left to right (most significant to least significant). You then take the remaining fractional part and repeat the process until the fraction reaches zero or you hit your hardware's bit-depth limit.
Worked Numeric Example: 0.6875
Let's convert the decimal fraction 0.6875 to binary.
- 0.6875 × 2 = 1.375 (Carry 1, remaining fraction 0.375)
- 0.375 × 2 = 0.75 (Carry 0, remaining fraction 0.75)
- 0.75 × 2 = 1.5 (Carry 1, remaining fraction 0.5)
- 0.5 × 2 = 1.0 (Carry 1, remaining fraction 0.0)
Reading the carried integers top to bottom, the binary representation is 0.1011. Because the remaining fraction hit exactly zero, this is a terminating binary fraction.
But what happens when the fraction doesn't terminate? Let's look at 0.1 (one-tenth).
- 0.1 × 2 = 0.2
- 0.2 × 2 = 0.4
- 0.4 × 2 = 0.8
- 0.8 × 2 = 1.6
- 0.6 × 2 = 1.2
- 0.2 × 2 = 0.4 (The sequence 0011 repeats infinitely)
The binary equivalent of 0.1 is 0.0001100110011... repeating forever. This infinite repetition is the root cause of quantization error and floating-point drift in embedded systems.
Where You Meet This in Practice: DACs and PWM
You rarely write raw binary fractions like 0.1011 directly into code. Instead, you meet this concept when mapping a desired physical output (like a voltage or a motor speed percentage) to a microcontroller's hardware register limits. Hardware registers are integer-based. If you want to output a fraction of a reference voltage, you must scale your decimal fraction to the maximum integer value of the register's bit-depth.
Consider the ESP32's built-in 8-bit DAC. An 8-bit register holds integer values from 0 to 255. If your reference voltage is 3.3V, each binary step (Least Significant Bit, or LSB) represents:
1 LSB = 3.3V / 255 = 12.94 mV
If your control algorithm demands exactly 1.5V, you first find the decimal fraction of the reference:
1.5V / 3.3V = 0.454545...
Next, you scale this fraction to the 8-bit register space by multiplying by 255:
0.454545... × 255 = 115.909
Since the hardware register only accepts integers, you round to 116. In binary, 116 is 01110100. You have just performed a practical fractional decimal to binary mapping. The actual voltage output will be 116 × 12.94 mV = 1.501V, introducing a minor 1mV quantization error.
The Quantization Trap: Why 0.1 Breaks Your Code
The most common confusion in embedded math is assuming that clean decimal fractions (like 0.1, 0.2, or 0.3) have clean binary equivalents. As proven in the algorithm section, they do not.
If you use standard IEEE 754 32-bit floating-point math (float in C/C++) to accumulate a 0.1 decimal fraction in a tight control loop, the infinite binary repetition gets truncated at the 23rd mantissa bit. Over thousands of iterations in a PID controller or a digital filter, this truncation error accumulates. Your system might expect a value of 10.0, but the floating-point register holds 9.999998. If your code uses a strict equality check (if (voltage == 10.0)), the condition will fail, and your state machine will hang.
This is why professional firmware engineers avoid floating-point math inside hardware Interrupt Service Routines (ISRs). Instead, they use fixed-point arithmetic, scaling all decimal fractions into large integers (e.g., multiplying everything by 10,000) before executing the binary math, completely bypassing the fractional binary trap.
Decision Path: Choosing Your Fractional Representation
How you handle fractional decimals depends entirely on your hardware constraints and timing requirements. Use the decision matrix below to select the right approach for your next PCB or firmware build.
| Application Scenario | Timing Constraint | Concrete Pick / Action |
|---|---|---|
| Simple LED dimming or basic heater control | Slow (Human-scale, >10ms) | Use 8-bit Integer PWM. Map 0.0-1.0 fraction to 0-255. Accept the quantization error. |
| PID Motor Control Loop (ISR) | Fast (<100μs per loop) | Use Q15 Fixed-Point Math (16-bit integers). Multiply fractions by 32768. Avoid floats in the ISR. |
| High-Fidelity Audio / Sine Wave Generation | Continuous (44.1kHz+) | Use a 16-bit External DAC (e.g., TI DAC8562) via SPI. Pre-calculate fractional lookup tables in flash memory. |
| Complex Sensor Fusion (Kalman Filters) | Moderate (Main loop, >1ms) | Use 32-bit Float (IEEE 754) on a 32-bit MCU (ESP32/STM32) with a hardware FPU. Cast to int only at the final output stage. |
Default Recommendation: If you are building a general-purpose sensor or actuator interface and are unsure which path to take, default to 16-bit unsigned integer scaling. Multiply your 0.0 to 1.0 decimal fraction by 65535 and store it as a uint16_t. This provides 65,536 discrete steps—more than enough resolution for 95% of hobbyist and industrial analog outputs—while keeping the math strictly in the integer domain, ensuring fast execution and zero floating-point drift.
FAQ: Common Binary Fraction Pitfalls
Why does my multimeter read a different voltage than my code calculated?
Microcontroller DACs are notoriously uncalibrated out of the box. The ESP32's internal DAC, for example, can have a non-linearity error of up to ±5%. Furthermore, if you are drawing more than a few milliamps from the DAC pin, the internal resistance causes a voltage drop. Always buffer your DAC output with an op-amp (like the MCP6001) configured as a voltage follower to isolate the microcontroller pin from your load.
Can I just use the 'double' data type to fix precision errors?
Using a 64-bit double pushes the infinite binary repetition further down the mantissa, reducing the visible error, but it does not eliminate it. More importantly, most 32-bit microcontrollers (like the standard ESP32 or ARM Cortex-M0) do not have a 64-bit hardware Floating Point Unit (FPU). The compiler will silently fall back to software emulation, which can make your math operations 10x to 50x slower, potentially causing watchdog timer resets in time-critical code.
How do I convert a binary fraction back to decimal in my head?
Read the bits to the right of the binary point as negative powers of two. For example, in 0.101, the first bit is 2-1 (0.5), the second is 2-2 (0.25), and the third is 2-3 (0.125). Add the values where the bit is '1': 0.5 + 0.125 = 0.625.






