A formula can be implemented perfectly and still give the wrong answer

I spent a while this year writing a small zero-dependency library of health and fitness formulas — BMI, Mifflin-St Jeor, the US Navy body-fat equation, FFMI, Epley and Brzycki, Karvonen. Thirty-odd functions, no dependencies, ESM, one file.

It should have been a boring job. It mostly was. But three things came out of it that I think generalise well beyond fitness maths, and one of them genuinely changed how I think about what “correct” means in a library.

The boring part: these equations get reimplemented constantly, and quietly wrong

Search for any of these formulas and you will find dozens of implementations. A lot of them are subtly broken, in ways that never throw and never look wrong:

  • The wrong coefficient set. The Navy body-fat equation has separate male and female forms, and separate metric and imperial constants. Four combinations, and three of them are wrong for any given call.
  • The imperial equation fed metric input. Nothing errors. You just get a number that is wrong by a believable margin, which is the worst kind of wrong.
  • Rounding in the middle. More on this below, because it turned out to be the interesting one.

None of these produce a NaN or a stack trace. They produce a plausible number. That is the entire problem: there is no failure signal, so the bug survives indefinitely.

My response was unremarkable — every function names the paper it came from in a docblock, and nothing is rounded inside the library. You round for display, because only you know how many decimal places your UI has room for.

The interesting part: rounding order is observable, so it has to be pinned

Total daily energy expenditure is BMR times an activity multiplier. Trivial. Except: do you round the BMR before multiplying, or round only the final figure?

It matters, and it is measurable:

const args = { sex: 'female', kg: 70.5, cm: 167, age: 41 };
const raw = bmrMifflinStJeor(args);   // 1382.75

Math.round(Math.round(raw) * 1.725);  // 2386  <- round first
Math.round(raw * 1.725);              // 2385  <- round last

One kilocalorie. Utterly meaningless physiologically — nobody’s diet is sensitive to 1 kcal, and the underlying equation has a standard error hundreds of times larger.

But it is not meaningless as a library contract. Two callers doing “the same” calculation get different numbers, and neither can tell why. Someone comparing my output against another tool finds an off-by-one and reasonably concludes one of us has a bug. So the order is pinned and there is a test that fails if anyone changes it:

test('tdee — rounding order is observable, so it is pinned', () => {
  // 70.5 kg gives a fractional BMR; rounding first vs last must differ here.
  const args = { sex: 'female', kg: 70.5, cm: 167, age: 41 };
  const raw = bmrMifflinStJeor(args);
  assert.notEqual(Math.round(raw), raw, 'test input must produce a fractional BMR');
  const r = tdee({ ...args, activity: 'active' });
  assert.equal(r.tdee, Math.round(Math.round(raw) * 1.725));
});

Note the second assertion. The test asserts its own premise — that this input actually produces a fractional BMR. Without it, someone tweaking the Mifflin-St Jeor constants could make the input round cleanly, and the test would keep passing while testing nothing at all. A test whose premise can silently evaporate is worse than no test, because it reports success.

That is the pattern I would take to any numeric library: when a choice is arbitrary but observable, pin it in a test, and make the test verify that its own scenario is still meaningful.

The part that actually changed my mind: correct is not the same as current

Here is the one I did not see coming.

The US Navy body-fat equation — Hodgdon & Beckett, 1984 — is the most widely implemented formula in this entire space. My implementation of it is correct. It matches the paper, it matches the reference values, it is tested to one decimal place.

And partway through the year it stopped being the right answer to the question most people are actually asking.

The US Department of Defense moved every service to a waist-to-height ratio screen on 1 January 2026, and the Army implemented it on 7 July 2026 — retiring both the height/weight tables and the circumference tape test that produced a body-fat percentage. Someone calling a function to check whether they meet a service standard is now being measured against something that no longer exists. The arithmetic is still right. The answer is wrong.

Out of curiosity I audited the calculators that rank for this. Of nine pages I could verify, eight were still running the retired method. Several advertise themselves as updated for 2026. One stamps “Last Logic Update: July 2026” in its footer — the month of the change — while running a formula that was superseded in 2023.

I do not think those are careless people. I think it is a structural blind spot in how we test numeric code. My test suite verifies that bodyFatNavy matches Hodgdon & Beckett. There is no test anywhere that could tell me Hodgdon & Beckett stopped being the standard, because that fact does not live in the code, the inputs, or the outputs. It lives in a policy document I had no reason to read.

The best I have come up with is modest: say plainly, in the docs, what a function is for and what it is not, and give the reader the current alternative. So the README now says the Navy equation is named for its origin and not its current use, notes that it remains a sound field estimate, and points at waistToHeightRatio for the standard that actually applies. Whether anyone reads that is another question — but at least the library is no longer silently implying something false.

If you maintain anything that encodes an external standard — tax bands, postal formats, accessibility thresholds, compliance rules — I would ask the same question I had to ask myself: what would have to change in the world for my correct code to start giving wrong answers, and would I ever find out?

Small thing: throw, do not return NaN

Last one, quickly. Every function validates and throws:

bodyFatNavy({ sex: 'male', neckCm: 90, waistCm: 85, heightCm: 175 });
// RangeError — waist must exceed neck

A neck larger than a waist is not a number problem, it is a measurement problem, and NaN propagates silently through arithmetic until it surfaces somewhere unrelated. Throwing at the boundary makes the caller deal with it while they still have the context to understand it.

The library

health-fitness-formulas — MIT, zero dependencies, ESM, Node 18+. 31 tests via node --test, no test framework.

npm install health-fitness-formulas

These are the implementations behind the calculators on Healthy Calculator Hub, and the suite asserts they stay in agreement with what the site serves. If you spot a coefficient I have got wrong, I would genuinely like to know.

One honest caveat, since it is a health topic: every function returns a population-level estimate. None is diagnostic, and body-fat categories in particular are conventions rather than an agreed international standard. It does arithmetic on published formulas and shows its working. That is all it does.

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Linux Troubleshooting Workflow for Beginners: A Step-by-Step Guide

Related Posts