A binary fraction is a base-2 number representing a value less than one, where each digit to the right of the binary point corresponds to a negative power of two, and converting it to decimal means summing those powers to find its base-10 equivalent. If you are programming microcontrollers, configuring PWM timers, or writing I2C payloads for digital-to-analog converters (DACs), understanding how to translate a fraction binary to decimal (and vice versa) is not just an academic exercise—it is the difference between a precise 1.500V reference and a stuttering motor driver.
The Core Math: Converting Fraction Binary to Decimal
Think of a standard imperial ruler. The first mark after the inch is the half-inch (1/2), the next is the quarter-inch (1/4), then the eighth (1/8). Binary fractions work exactly the same way, but they stop at the physical limits of your hardware register. In base-10, the number 0.6875 means $6/10 + 8/100 + 7/1000 + 5/10000$. In base-2, the positions to the right of the binary point represent $2^{-1}$ (0.5), $2^{-2}$ (0.25), $2^{-3}$ (0.125), and $2^{-4}$ (0.0625).
0.1011 converts to the decimal value 0.6875.
Here is the step-by-step breakdown of that conversion:
- Identify the bit positions: The bits are 1 (position -1), 0 (position -2), 1 (position -3), and 1 (position -4).
- Apply negative powers of 2: $(1 \times 2^{-1}) + (0 \times 2^{-2}) + (1 \times 2^{-3}) + (1 \times 2^{-4})$.
- Calculate the decimal weights: $0.5 + 0 + 0.125 + 0.0625$.
- Sum the values: $0.5 + 0.125 + 0.0625 = 0.6875$.
When you read a datasheet for a 12-bit ADC like the TI ADS1115, the Least Significant Bit (LSB) weight is often defined as a binary fraction of the full-scale range (FSR). If your FSR is 4.096V, 1 LSB is exactly $2^{-12}$ of the range, which translates to a decimal step size of 1mV. Misinterpreting this fractional weight is a primary source of scaling errors in sensor data.
Where You Meet This in Practice: ADCs, DACs, and PWM
In a real circuit, you rarely type 0.1011 into your code. Instead, you interact with hardware registers that implicitly treat integer values as binary fractions of a reference voltage or a timer period. What this changes in your installation is the physical output of your system.
- DAC Output Voltage: A 12-bit MCP4725 DAC maps the integer range 0–4095 to 0V–VDD. When you send the integer
1862, the hardware interprets it as the binary fraction0.11101000110of the 3.3V reference. - PWM Duty Cycles: If you configure an ESP32 LEDC timer for 10-bit resolution (0–1023), a 33.3% duty cycle requires you to convert the decimal fraction
0.333into a binary fraction, multiply by 1024, and write the resulting integer to the compare register. - PLL Clock Dividers: Fractional-N phase-locked loops in RF transceivers use binary fraction accumulators to generate non-integer clock multiples. A miscalculated fraction here results in phase noise and failed wireless links.
Real-World Scenario Walkthrough: The MCP4725 DAC Overvoltage
To see why the distinction between a decimal fraction and a binary fraction matters on the bench, let us look at a common I2C packing failure.
The Setup: You need to output exactly 1.500V from an MCP4725 12-bit DAC powered at 3.3V to bias an op-amp. You are writing a custom bit-banging I2C routine in C++ because the standard library is bloated for your ATtiny85.
The Numbers:
Target decimal fraction = $1.5V / 3.3V = 0.454545...$
Multiply by $2^{12}$ (4096) to get the register value: $0.454545 \times 4096 = 1861.81$, which rounds to 1862.
The binary representation of 1862 is 11101000110.
As a binary fraction, this is 0.11101000110.
The Outcome: You flash the code, probe the DAC output with your multimeter, and read 0.749V—exactly half of your target. The op-amp fails to bias, and the audio signal clips.
What Went Wrong: The MCP4725 requires a specific I2C byte sequence. The 12 bits must be packed into two bytes: Byte 1 holds the top 4 data bits (D11-D8), and Byte 2 holds the bottom 8 (D7-D0). Because the developer was thinking in terms of the binary fraction rather than the integer register value, they incorrectly assumed the Most Significant Bit (MSB) of the fraction ($2^{-1}$) belonged in the lowest available bit of the first payload byte. They effectively shifted the entire binary fraction right by one position, sending 01110100011 (decimal 931) instead of 11101000110 (decimal 1862). The DAC output $931 / 4096 \times 3.3V = 0.749V$. Always treat the hardware register as an integer that represents a fraction, not as a literal string of fractional bits to be manually aligned without checking the datasheet's byte map.
Common Confusions: Fixed-Point vs. Floating-Point and Rounding Traps
When engineers search for fraction binary to decimal conversion, they frequently confuse three distinct concepts:
0.101 is a pure mathematical value. The IEEE 754 floating-point standard stores decimals using a sign bit, an exponent, and a mantissa. If you try to read a float variable's memory address in C++ and interpret the raw bits as a simple binary fraction, your results will be completely wrong. Use fixed-point integer math for hardware registers.
Another major trap is the off-by-one denominator error. When converting a decimal fraction to a DAC register value, developers often multiply by $(2^n - 1)$ instead of $2^n$. For a 12-bit DAC, they multiply by 4095 instead of 4096. While the error is small (less than 1 LSB), in high-precision metrology or closed-loop PID control systems, this systematic offset causes a steady-state error that the integral windup struggles to correct. According to Texas Instruments' data converter application notes, the full-scale range is defined by $2^n$ steps, making $2^n$ the correct multiplier for fractional scaling.
Quick Reference: Binary Fraction to Decimal Cheat Sheet
Keep this table at your workbench when debugging PWM duty cycles or calculating ADC LSB weights. It maps the first 8 bits of a binary fraction to their exact decimal equivalents.
| Bit Position | Binary Weight | Fraction | Exact Decimal | Common Use Case |
|---|---|---|---|---|
| -1 (MSB) | $2^{-1}$ | 1/2 | 0.5000 | 50% PWM Duty Cycle |
| -2 | $2^{-2}$ | 1/4 | 0.2500 | 8-bit DAC Quarter Scale |
| -3 | $2^{-3}$ | 1/8 | 0.1250 | Octave Divider in Audio |
| -4 | $2^{-4}$ | 1/16 | 0.0625 | 16-bit Timer Prescaler |
| -5 | $2^{-5}$ | 1/32 | 0.03125 | Stepper Motor Microstepping |
| -6 | $2^{-6}$ | 1/64 | 0.015625 | Current Sense Amplifier Gain |
| -7 | $2^{-7}$ | 1/128 | 0.0078125 | High-Res Sine Lookup Table |
| -8 (LSB) | $2^{-8}$ | 1/256 | 0.00390625 | 8-bit DAC 1 LSB Step |
FAQ: Binary Fractions in Embedded Systems
Q: Why does my ESP32 PWM output 33.3% duty cycle look jittery on the scope?
A: The decimal fraction 0.333 cannot be represented perfectly in binary. It results in a repeating binary fraction (0.01010101...). When you truncate this to a 10-bit register (value 341), the actual duty cycle is $341/1024 = 33.3007\%$. The jitter you see is likely not the math, but the RTOS task scheduler interrupting the timer configuration. Use the ESP32's dedicated hardware LEDC peripheral and ensure the timer configuration is locked before starting the output.
Q: How do I convert a repeating decimal fraction to binary in C++ without losing precision?
A: You cannot store infinite repeating fractions in finite registers. Instead of trying to convert the fraction directly, use integer scaling. If you need 1/3 of a 4096-step DAC, do not calculate 0.3333 * 4096. Calculate 4096 / 3 using integer division, which yields exactly 1365. This avoids floating-point rounding errors entirely. For more on digital signal precision, refer to the All About Circuits digital arithmetic textbook.
Q: Does the binary fraction conversion change if I am using a signed (two's complement) ADC?
A: Yes. In a signed 16-bit ADC (like the ADS1115), the MSB is the sign bit, not a fractional weight. The remaining 15 bits represent the binary fraction of the positive or negative full-scale range. You must strip the sign bit, convert the remaining 15 bits from fraction binary to decimal, and then apply the negative sign manually in your code.






