Mathematics
Fractions
Decimal Conversion
Algebra
Number Theory

Algorithm for simplifying decimal to fractions

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Turning a decimal into a fraction looks simple until you care about correctness. The reliable algorithm depends on whether the input is an exact terminating decimal such as 12.375, an intentionally repeating value such as 0.333..., or a rounded floating-point approximation coming from a computer.

Exact Algorithm for Terminating Decimals

For a terminating decimal written in base ten, the conversion is direct:

  1. Remove the decimal point.
  2. Use a denominator of 10^n, where n is the number of digits after the point.
  3. Reduce the fraction by dividing numerator and denominator by their greatest common divisor, or GCD.

For example, 12.375 becomes 12375 / 1000. The GCD of 12375 and 1000 is 125, so the simplified fraction is 99 / 8.

That algorithm is mathematically exact, but only if the decimal is stored exactly. This is why string input or decimal types are safer than binary floating-point values such as double.

A Practical Implementation

In Python, the Decimal type is a good match because it preserves the base ten representation of the input string. The code below converts a terminating decimal string into a reduced fraction.

python
1from decimal import Decimal
2from math import gcd
3
4
5def decimal_to_fraction(text: str) -> tuple[int, int]:
6    value = Decimal(text)
7    sign, digits, exponent = value.as_tuple()
8
9    integer_digits = int("".join(str(d) for d in digits)) if digits else 0
10    if sign:
11        integer_digits = -integer_digits
12
13    if exponent >= 0:
14        numerator = integer_digits * (10 ** exponent)
15        denominator = 1
16    else:
17        denominator = 10 ** (-exponent)
18        numerator = integer_digits
19
20    factor = gcd(abs(numerator), denominator)
21    return numerator // factor, denominator // factor
22
23
24print(decimal_to_fraction("12.375"))   # (99, 8)
25print(decimal_to_fraction("0.75"))     # (3, 4)
26print(decimal_to_fraction("-1.20"))    # (-6, 5)

This works because Decimal("0.75") really means seventy-five hundredths. By contrast, float(0.75) is safe here, but many values such as 0.1 are not represented exactly in binary floating-point.

Why Floating-Point Inputs Cause Confusion

Suppose a program receives the value 0.1 as a double. Internally, that may be closer to 0.10000000000000000555... than to an exact one tenth. If you build a fraction from that raw binary approximation, the result can be unexpectedly large.

In other words, there are two different problems:

  • convert an exact decimal string to a fraction
  • approximate a real number with a simple fraction

The first problem has the clean GCD-based solution above. The second is an approximation problem and usually calls for continued fractions or a denominator limit.

Repeating Decimals Need a Different Method

Repeating decimals are rational numbers, but they are not terminating decimals, so the denominator is not just a power of ten. The standard trick is to use algebra.

Take 0.333...:

  1. Let x = 0.333...
  2. Multiply by 10, giving 10x = 3.333...
  3. Subtract the first equation from the second, giving 9x = 3
  4. Solve for x, so x = 3 / 9 = 1 / 3

For 0.142857142857..., the repeating block has length six, so multiply by 10^6, subtract, and simplify:

text
1x = 0.142857142857...
21000000x = 142857.142857...
3999999x = 142857
4x = 142857 / 999999 = 1 / 7

If you are writing software, repeating decimals must usually be entered with explicit notation such as 0.(3) or 2.1(6). Without that, the machine only sees a finite approximation.

When You Need Approximation Instead of Exact Conversion

Sometimes the source is not an exact decimal string. It might be a measurement like 3.14159, and the real task is to find a "nice" fraction close to it. In that case, continued fractions are the standard approach because they produce the best rational approximations for a denominator budget.

For example, 3.14159 can be approximated as 355 / 113, which is much better than using the direct terminating-decimal conversion 314159 / 100000.

That distinction matters in user interfaces. If the user typed the number, exact conversion is usually right. If the number came from sensors, simulation, or binary floating-point math, approximation may be more useful.

Common Pitfalls

The biggest mistake is starting from a binary floating-point number and assuming it is the same as the decimal the user typed. That is where giant numerators and denominators come from.

Another mistake is forgetting to reduce the fraction with the GCD. The unsimplified result is mathematically correct, but it is rarely what people want.

Repeating decimals are also often mishandled. A value displayed as 0.333333 is not automatically the exact fraction 1 / 3; it may just be a rounded display of some underlying value.

Finally, negative numbers should keep the sign on the numerator, while the denominator stays positive. That keeps the result normalized and easier to compare.

Summary

  • Terminating decimals convert exactly by removing the point and using a power-of-ten denominator.
  • Simplify the result with the GCD.
  • Use decimal strings or Decimal, not binary floating-point, when exactness matters.
  • Repeating decimals need an algebraic method, not just 10^n.
  • If the real goal is a simple approximation, use a rational-approximation algorithm instead of exact conversion.

Course illustration
Course illustration

All Rights Reserved.