I built a weight converter. The interesting part is not the math — it is one line long. The interesting part is where everyone puts the rounding.
Convert 70 kg to pounds, round to 154 lb, convert back: 69.85 kg. You just lost 0.15 kg to a round trip that never needed to happen. Do that across a spreadsheet of body weights or shipping weights and the drift becomes real error. So the converter I built stores full precision and rounds only for display. Here is why that is the right call, and how the pieces fit together.
The factor is a definition, not a measurement
One pound is defined as exactly 0.45359237 kilograms. That makes the reverse factor exact too:
const KG_PER_LB = 0.45359237; // exact, by definition const LB_PER_KG = 1 / KG_PER_LB; // 2.2046226218... There is no sensor noise here, no calibration drift. Kilograms and pounds are tied by fixed definitions, so a converter has no excuse for being approximately right. "1 kg = 2.2 lb" is a display choice, not a fact about the world — and the moment a tool treats the display value as the stored value, it starts inventing error.
That is lesson one: keep the full-precision number internally, and let the user pick the display precision. My converter has a precision selector for exactly this reason. The stored value never changes; only the digits on screen do.
Stones, pounds, and ounces are distinct units
The second trap is treating weight units as one sliding scale. They are not. A stone is 14 pounds, and 14 pounds is 6.35029 kg — but a stone is still its own unit, and people write body weight as "11 stone 4 lb", not as a decimal.
const UNITS = { kg: 1, g: 0.001, lb: 0.45359237, oz: 0.028349523125, st: 6.35029318, // 14 lb, exact }; Every unit converts through kilograms as the base. Add a unit and you add one line — no special cases, no conversion matrix that drifts out of sync.
Parsing "7 lb 4 oz" the way people write it
Nobody says "7.25 pounds" out loud. They say "seven pounds four". So the converter's smart input reads compound values directly:
function parseCompound(input) { // "7 lb 4 oz" -> kilograms const parts = [...input.matchAll(/([\d.]+)\s*(kg|g|lb|oz|st)\b/gi)]; let kg = 0; for (const [, value, unit] of parts) { kg += parseFloat(value) * UNITS[unit.toLowerCase()]; } return kg; // 7 lb 4 oz -> 3.289 kg } Two details matter. First, each part converts through the exact factor before anything is added — never round the parts and then sum them. Second, the parser is deliberately strict about unit tokens: "7 lb 4 oz" parses, "7 pounds 4 ounces" should too in a real product, but free-text words like "about" must not silently become zero.
The same input box also accepts cross-category phrases like "10 km to miles" or "5'8\" to cm" — the converter family shares one smart-input parser, and each tool only answers for its own units.
Display rounding is a UI decision, not a math step
Here is the rule I settled on, and the one I would defend in review:
function display(valueKg, toUnit, decimals) { const raw = valueKg / UNITS[toUnit]; // full precision, always return raw.toFixed(decimals); // rounding happens here, once } Round once, at the edge, for human eyes. Never round an intermediate value that another calculation will consume. If the user picks 2 decimals, 70 kg shows as 154.32 lb — and converting back still starts from 70 kg, not from 154.32.
This is also why "2.2" as a stored factor is a bug, not a simplification. Store 2.2046226218, display 2.20. The cost is nothing; the correctness is free.
The baking caveat no converter can fix
One thing the code cannot do: convert cups to grams. A cup is a volume, a gram is a mass, and the bridge between them is the ingredient's density. The converter's own FAQ says this plainly — cups-to-grams depends on the ingredient. Commonly used approximations are 1 cup of all-purpose flour ≈ 120 g, 1 cup of granulated sugar ≈ 200 g, and 1 cup of butter ≈ 227 g, but those are averages, not definitions.
A converter that quietly bakes in one density and presents the result as exact is worse than one that refuses. If your tool offers cups, label the density, let the user change it, and say the result is approximate. Honest imprecision beats confident error.
Why it runs entirely in the browser
The converter is part of ToolkitLoop, a set of free tools I built that run entirely in your browser — no sign-up, no uploads, nothing stored on a server. Weight numbers are often health data or business data, and a browser-local tool has nothing to leak because there is nothing to send.
Try it: Weight Converter. Type "7 lb 4 oz" and watch it come back as 3.29 kg. Then change the precision selector and notice the stored value never moves — only the digits on screen do.
Here is the question I keep coming back to: should a converter ever round its stored value, or is display-only rounding the only honest default? And has a round-trip conversion ever bitten you — a recipe, a shipping label, a gym log? I am genuinely curious where the 0.15 kg went in your workflow.
