DEV Community

Cover image for How to Convert Decimals to Fractions: 3 Steps With Examples

How to Convert Decimals to Fractions: 3 Steps With Examples

bowen Tse on October 05, 2026

Your API returns 0.375. The design mock says "⅜". The recipe your app is scaling says 0.666 cups but the user owns measuring cups marked in quarter...
Collapse
 
alewx profile image
alex •

i use fraction.js to avoid floating‑point surprises and force rounding to the nearest 1/8 for UI labels
have you run into edge cases with recurring decimals like 1/3?

Collapse
 
bowentse profile image
bowen Tse •

Great question — this is exactly the boundary where the snippet in the article falls over, and honestly it's the reason the tool exists. Two different failure modes, needing two different fixes:

1. Float dust. d.toString() on something like 0.1 + 0.2 gives you "0.30000000000000004", so your place-count is wrong before the math even starts. fraction.js dodges this by parsing the string representation instead of trusting the float — same advice I'd give anyone: never let the float touch the algorithm, parse the input string.

2. The 1/3 boundary. This one isn't really a math problem, it's a UX decision. Is 0.3333333333 a terminating decimal that happens to be near 1/3, or did the user mean one-third and just not know repeat notation? No algorithm can read that intent, so guessing is wrong in one direction or the other. That's why the tool refuses to guess and makes it explicit instead:

  • If you mean exactly one-third, type 0.(3) — parentheses mark the repeating part, and you get exactly 1/3 with the algebraic working shown in the steps panel.
  • If you typed a long terminating tail, the "maximum denominator" control shows the nearest practical fraction and its error, so you decide whether the snap is acceptable for your case (CNC readout: yes; ledger math: probably not).

For the tolerance approach in your own code: continued fractions with a denominator cap is the standard trick — it's what produces 22/7-style "best approximations". That's essentially what fraction.js does under the hood with its epsilon.

Rule of thumb: parse strings, not floats; make repeats explicit notation; and whenever you approximate, show the error. What were you building, out of curiosity?

Collapse
 
alewx profile image
alex •

if you need exact counts, avoid floating math entirely, store millimeters as integers or use a decimal library, string parsing just masks the underlying precision problem

Thread Thread
 
bowentse profile image
bowen Tse •

Fair point, and I agree with the distinction: if your pipeline needs exact counts (accumulated measurements, money math), integers or a decimal type are the right call — recurring cases like 1/3 and running totals are exactly where float breaks down.

This converter sits at the other end of the problem: it takes what a person typed (so the typed digits are the source of truth) and reduces it to a fraction — useful for one-off conversions and UI labels like yours. It doesn't try to be a calculation engine, and it shouldn't be trusted as one. I'll call that boundary out more clearly in the article.

Thanks for the follow-up — and quick disclosure since it's relevant: I'm the founder of ToolkitLoop (toolkitloop.com), a set of free browser-side tools that never upload anything, and this converter is one of them.

Thread Thread
 
alewx profile image
alex •

right, so the parser should keep the raw string until you know the target type, otherwise you lose precision or locale info

Thread Thread
 
bowentse profile image
bowen Tse •

Exactly right — and that's actually how this converter is built. The input never passes through a float: we take the raw string, count the decimal places, and reduce (0.125 → 125/1000 → 1/8). No binary rounding ever touches the value, which is precisely what keeps the 0.1 + 0.2 class of dust out.

Fair point on locale too — comma separators like 1,5 are exactly the kind of thing a raw-string-first parser has to decide on deliberately. Right now the tool expects a period, so I've logged that as feedback. Good catch.