Waist-to-height ratio (WHtR) looks like the easiest calculator you could write: divide one number by another. It's also a good example of how a "trivial" calculator goes wrong in production. Users type centimeters into an inches box. Floating point makes a value that should sit exactly on a limit land a hair above it. A display rounded to two decimals disagrees with the pass/fail check underneath it.
This post walks through a small, dependency-free JavaScript module for WHtR and the tests that keep it honest. The limit in the examples (0.5) is only an illustration for the code. If you build a calculator for a real standard, take the threshold from the governing document and cite it on the page.
The core: one unit internally
The first decision is to convert everything to one unit as soon as input arrives, then do all comparisons in that unit. Mixing units in the middle of the logic is where most bugs start.
const IN_PER_CM = 1 / 2.54;
function toInches(value, unit) {
if (!Number.isFinite(value) || value <= 0) throw new RangeError("measurement must be a positive number");
if (unit === "in") return value;
if (unit === "cm") return value * IN_PER_CM;
throw new TypeError(`unknown unit: ${unit}`);
}
function whtr({ waist, height, waistUnit = "in", heightUnit = "in" }) {
const w = toInches(waist, waistUnit);
const h = toInches(height, heightUnit);
return w / h;
}
// Compare against a limit without letting float noise or display rounding flip the answer.
function withinLimit(ratio, limit) {
const EPS = 1e-9;
return ratio <= limit + EPS;
}
// Largest waist (inches) allowed for a given height and limit, rounded DOWN to the tape's resolution.
function maxWaist(heightIn, limit, step = 0.5) {
const raw = heightIn * limit;
return Math.floor((raw + 1e-9) / step) * step;
}
module.exports = { whtr, withinLimit, maxWaist, toInches };
if (require.main === module) {
const assert = require("assert");
// Same person, two unit systems: the ratio must agree.
const a = whtr({ waist: 34, height: 70 });
const b = whtr({ waist: 86.36, waistUnit: "cm", height: 177.8, heightUnit: "cm" });
assert(Math.abs(a - b) < 1e-9);
// Boundary: exactly on the (illustrative) limit passes, a hair over does not.
assert(withinLimit(35 / 70, 0.5));
assert(!withinLimit(35.1 / 70, 0.5));
// Mixed units
const c = whtr({ waist: 34, height: 177.8, heightUnit: "cm" });
assert(Math.abs(c - a) < 1e-9);
// maxWaist rounds down
assert.strictEqual(maxWaist(69, 0.5), 34.5);
assert.strictEqual(maxWaist(69.9, 0.5), 34.5);
assert.strictEqual(maxWaist(70, 0.5), 35);
// Bad input
assert.throws(() => whtr({ waist: 0, height: 70 }), RangeError);
assert.throws(() => whtr({ waist: 34, height: 70, waistUnit: "ft" }), TypeError);
console.log("all tests passed", a.toFixed(4));
}
A few things worth noticing in that module.
Validation happens at the boundary. toInches rejects zero, negative numbers, NaN, and unknown units. A calculator that quietly returns Infinity or NaN teaches users to distrust the whole page. Throwing a specific error lets the UI show a specific message.
Units are explicit. Waist and height each carry their own unit, so a person can enter a waist in inches and a height in centimeters and still get the right ratio. People do this more often than you would guess, because tape measures and doctor's-office height charts don't always agree on units.
The comparison uses a small epsilon. Floating point means 35 / 70 is fine, but a value derived from a centimeter conversion might come out as 0.5000000000000001. If the rule says "at or below the limit," a person exactly on the limit must pass. The epsilon (1e-9) is far smaller than any real measurement resolution, so it only removes noise.
Rounding: decide what the user sees and what the code decides
There are two numbers in play: the exact ratio and the number you display. If you display 0.50 but the check used 0.5004, the page contradicts itself, and you will get a support email.
Two rules help:
- Decide pass/fail from the unrounded ratio, with the epsilon above.
- If the source document specifies how to round, implement that exactly and test it. If it doesn't, display more digits than you think you need, or say "rounded for display."
The maxWaist function shows the same idea in reverse. When a user asks "what is the largest waist I can have at my height," the answer should be rounded down to the resolution of a tape measure. Rounding to the nearest value could tell someone 34.75 inches is fine when 34.5 is the real limit.
Tests that catch real bugs
The assert block at the bottom of the file is short but covers the failures I have seen most:
- Same person, different units. 34 inches at 70 inches tall must equal 86.36 cm at 177.8 cm. If this fails, your conversion constant or your order of operations is wrong.
- Exactly on the line. The boundary case should pass, and a tenth of an inch over should not.
- Mixed units. One input in inches and one in centimeters gives the same ratio.
- Rounding direction. The maximum-waist helper must never round up.
- Garbage in. Zero and unknown units throw typed errors.
If you want to go further, add a property test: for a fixed height, the ratio should never decrease as waist increases. And add a handful of cells copied by hand from the source document, so the tests don't only prove the code agrees with itself.
Presentation matters as much as math
A few UI details prevent most user mistakes:
- Put the unit toggle next to each field, not in a settings menu.
- Show the interpreted values back to the user ("34 in waist, 70 in height") so a typo is obvious.
- Write the source and effective date of any threshold next to the result, and say clearly that the page is an independent tool, not an authority on the standard.
I put these ideas into a free tool, AFTPTCalc, which has a WHtR calculator alongside military fitness-test calculators. The code above is a simplified teaching version, not the production code.
Takeaways
- Normalize units once, early, and validate hard.
- Compare with a tiny tolerance and decide from unrounded values.
- Round the "maximum allowed" direction deliberately.
- Test the boundary, the unit conversions, and the garbage inputs.
If you have run into other edge cases in measurement calculators, I'd like to hear about them in the comments.
Disclosure: I used an AI writing assistant to help draft and edit this post. I ran the code and its tests before publishing. The 0.5 limit is an illustration only.
Top comments (1)
The 'decide pass/fail from the unrounded ratio' is the single most important rule here. I've seen calculators that display 0.50 but fail the check because the underlying value was 0.5004. It's a support nightmare, and it's entirely avoidable.