No — an LLM should not perform the arithmetic itself. The model should name the operation and extract the operands; deterministic code should perform the arithmetic; the model should then explain a result it did not produce. A figure generated as tokens is well-formed, plausible and unverifiable at a glance. Call the pattern extract, compute, explain.
Ross Jones — Founder, The Hopium Lab. Last modified 22 July 2026. Engineering account, not legal advice.
Don't frontier models call Python automatically now?
Sometimes, and the decision to call is itself a probabilistic output. Anthropic's tool use documentation is explicit: "With the default tool_choice of {"type": "auto"}, Claude determines on each turn whether to call a tool or respond directly." Consumer chat products route plenty of arithmetic into a sandbox. The systems I audit that put a number in front of a paying customer are rarely a chat window with a sandbox attached — they are API calls in a pipeline, tools declared, choice left on auto. Nothing in the rendered response separates a computed number from a generated one. The reviewer cannot tell. Nor can the customer.
Leaderboard scores are earned on curated exams. Apple's GSM-Symbolic (v1 October 2024, v2 August 2025) regenerated GSM8K problems from templates and reported degradation across models, sharpest when an irrelevant clause was added. Treat that as directional only: a 2026 re-analysis (arXiv:2605.28700) refits the results with per-question random effects and finds only about half of twenty open-weight models change significantly, plus a shifted integer distribution in the benchmark itself. The honest reading is that a benchmark number is a claim about a benchmark. Nobody's score was earned on your scanned delivery note.
Why is a wrong number worse than a wrong sentence?
Because arithmetic failures are well-formed. Balter, Jerzak and Jerzak (arXiv:2604.18203, ACL Findings 2026) define an arithmetic load — the product of total and non-zero digit counts — and report multiplication accuracy that "falls sharply as C grows, often nearing zero by C > 100", while perception checks in the same trials score "near-perfect (> 99%)" across text, image and audio inputs. The model read the operands correctly and got the product wrong. The excuse that the model misread the invoice does not survive that result.
A hallucinated citation looks wrong the moment anybody checks it. A wrong total looks exactly like a right total. That asymmetry is the whole argument.
What does tokenisation actually break?
Alignment between how digits are chunked and how carries travel. Singh and Strouse (arXiv:2402.14903, 22 February 2024) found the GPT-3.5 and GPT-4 tokenizers carry "tokens for all 1-, 2-, and 3-digit strings", matched greedily left to right, so 12345 becomes 123|45. Carries run the other way. Comma-separating at inference — 8,302,080 rather than 8302080 — moved eight-shot addition accuracy from roughly 75.6% to roughly 97.8%. Twenty-two points from punctuation, with no change to the model, the prompt or the quantities.
Two caveats. That same paper found the gap narrows with scale, and chain-of-thought largely recovers the loss since models re-chunk for themselves. And the folk claim that Llama tokenises digit by digit was true of Llama 2, not Llama 3, which groups in threes.
The deeper reason survives every tokenizer change. Baeumel, van Genabith and Ostermann (arXiv:2502.19981, 27 February 2025) identify "a simple one-digit lookahead heuristic" — adequate for two operands, broken on multi-operand addition, failing exactly where "a one-digit lookahead is insufficient to account for cascading carries." Left-to-right generation fights right-to-left carry propagation, and no vocabulary fixes generation order.
Is the model just pattern-matching numbers it has seen?
No. It runs learned algorithms, which is the worse news. Kantamneni and Tegmark (arXiv:2502.00873) find numbers represented as a generalised helix and added by a "Clock" algorithm, causally verified in GPT-J, Pythia-6.9B and Llama3.1-8B over 10,000 addition problems in the 0–99 range. Anthropic's circuit tracing of 36+59 in On the Biology of a Large Language Model found two parallel pathways, one approximating the sum and one pinning the last digit. The machinery is learned, alien, and does not generalise past the range it was fitted on.
Does chain-of-thought fix it?
It buys a large real gain and lands nowhere near usable. On MedCalc-Bench — 1,047 instances across 55 medical calculation tasks, NeurIPS Datasets and Benchmarks — GPT-4 scores 20.82% zero-shot direct, 37.92% zero-shot chain-of-thought, 50.91% one-shot chain-of-thought. Terrible to unacceptable is not a fix.
A second objection, separate from accuracy and routinely conflated with it: visible working is not a record of the computation. Asked how it added 36 and 59, Claude reports columnar carrying — "I added the ones (6+9=15), carried the 1, then added the tens (3+5+1=9), resulting in 95." Circuit tracing shows nothing of the kind happened. Chen and colleagues at Anthropic (arXiv:2505.05410, May 2025) measured the same gap under answer-changing hints: Claude 3.7 Sonnet acknowledged the hint 25% of the time, DeepSeek R1 39%, falling to 20% and 29% for grader hacks.
The model's account of how it calculated something is generated by a different process from the calculation. A reviewer checking the visible steps is performing theatre with a straight face.
If you move the maths into code, are you done?
No — a calculator fixes roughly a third of it. MedCalc-Bench splits GPT-4's one-shot chain-of-thought errors three ways: 40% knowledge, the wrong equation chosen; 27% extraction, the wrong parameter pulled off the page; 33% computation, the arithmetic itself. Llama 3-70B splits 34/20/39, GPT-3.5 splits 36/30/31.
Moving the arithmetic into code fixes about a third of the problem. The model still chooses the formula and still picks the operands off the page, and no calculator saves anybody from either.
So the operation and the operands have to be inspectable artefacts before execution, not prose inside an answer. Goodell and colleagues (npj Digital Medicine 8:163, 2025) ran the ladder empirically: ChatGPT unaided gave "incorrect responses in one-third of trials (n = 212)" across 48 medical calculation tasks, then 10,000 further trials compared retrieval, a code interpreter, and named task-specific tools.
| What you bolt on | What it fixes | What stays broken | Evidence |
|---|---|---|---|
| Nothing — ask the model | Nothing | One in three clinical calculations wrong | Goodell et al., 2025 — 212 incorrect responses, 48 tasks |
| Chain-of-thought | Some formula recall, some arithmetic | Still a coin flip; the trace is not a record | MedCalc-Bench, GPT-4: 20.82% direct → 37.92% zero-shot CoT → 50.91% one-shot CoT |
| Retrieval over the formulas | Which equation applies | Extraction and the arithmetic | Goodell et al., 10,000 trials |
| General code interpreter | The arithmetic, when invoked | Formula choice, operand binding, the decision to invoke | Improved less than task-specific tools |
| Named task-specific tool | Arithmetic, formula binding, inspectable operands | Extraction — model-produced, still needs validating | 5.5-fold (88% vs 16%) for LLaMa-based and 13-fold (64% vs 4.8%) for GPT-based models |
Note the ordering, because it inverts the standard advice. Everybody says give it Python. The evidence says give it calculate_creatinine_clearance.
What does the contract look like in code?
One tool per named calculation, forced rather than offered, every operand carrying a reference back to a stored record. Money and dosage move as decimal strings, never floats.
{
"name": "calculate_invoice_total",
"strict": true,
"description": "Compute invoice and VAT totals. Never state a total that did not return from this tool.",
"input_schema": {
"type": "object",
"additionalProperties": false,
"required": ["currency", "rounding", "lines"],
"properties": {
"currency": { "type": "string", "enum": ["GBP", "EUR", "USD"] },
"rounding": { "type": "string", "enum": ["ROUND_HALF_EVEN", "ROUND_HALF_UP"] },
"lines": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["source_ref", "quantity", "unit_price_ex_vat", "vat_rate"],
"properties": {
"source_ref": { "type": "string" },
"quantity": { "type": "string", "pattern": "^-?\\d+(\\.\\d+)?$" },
"unit_price_ex_vat": { "type": "string", "pattern": "^-?\\d+(\\.\\d+)?$" },
"vat_rate": { "type": "string", "pattern": "^-?\\d+(\\.\\d+)?$" }
}
}
}
}
}
}
CALCULATION CONTRACT v1.0 — 22 July 2026 · The Hopium Lab
1 DECLARE Every figure shown to a human is EXTRACTED or COMPUTED. No third kind.
2 BIND Every operand carries a source_ref resolving to a stored record.
Unresolvable -> halt, queue for a human. No retry loop that ends
when the string finally parses.
3 FORCE tool_choice pinned to the tool; strict schema. Never {"type":"auto"}
on a path that reaches a ledger.
4 TYPE Decimal, never float. Scale and rounding mode declared at the call site
(half-even against half-up is a real reconciliation defect).
5 NAME One tool per named calculation. Not one general interpreter.
6 RENDER Displayed numbers templated from tool_result. Model tokens never
restate a total; prose is never the source of a figure.
7 LOG operation, operands + source_refs, tool version, raw result, rendered
string. Rebuildable without calling the model.
8 DIFF Recompute with a second implementation at write time. Mismatch halts,
never warns.
Fork the contract. Line 7 produces the capture an evidence layer exists to hold; retries need the idempotency discipline on top.
What happens when the number lands on an invoice or a dosage?
The figure stops being text and becomes a legal particular. Article 226 of the VAT Directive requires an invoice to state the taxable amount per rate, the unit price exclusive of VAT, the VAT rate applied, and the VAT amount payable (points 8 to 10). Three of those are computed figures and the fourth selects which computation applies. The UK equivalents sit in regulation 14 of the VAT Regulations 1995. A miscalculation is a defective invoice, not a typo.
Pointing at the model does not help. In Moffatt v. Air Canada, 2024 BCCRT 149, the tribunal rejected the argument that a chatbot was a separate entity, held the airline responsible for its own website, and awarded roughly CAD 650 plus interest and fees. Label it accurately: a liability precedent about ownership of output, on a bereavement-fare misstatement, not a calculation case.
Regulatory routing is where nearly every page on the subject is wrong. A dosage calculator is not high-risk via Annex III: point 5 reaches healthcare only through eligibility for essential public assistance benefits, life and health insurance risk pricing, and emergency-call evaluation including patient triage — diagnosis and clinical decision support appear nowhere in it. The route is Article 6(1), whose conditions are cumulative: the system is a safety component of, or is itself, a product covered by Annex I harmonisation legislation, and that product requires third-party conformity assessment. Point 5 does cover systems intended to evaluate creditworthiness or establish a credit score, excluding fraud detection — so a consumer affordability engine can land in Annex III, subject to the Article 6(3) derogation for narrow procedural tasks. Which way any given system falls is a documentation question, not an architecture question. The Digital Omnibus deferred stand-alone Annex III obligations to 2 December 2027 and Annex I embedded systems to 2 August 2028. Architecture supports a conformity case. It never confers one.
How does extract, compute, explain fail in production?
Seven ways, all found by reading code rather than architecture diagrams.
- Auto-tool drift. Tools declared,
tool_choiceleft on auto, the model answering from tokens deep in a long context. - Restated totals. The tool returns the right figure, the model retypes it into prose, one digit moves, and the log still says the calculation passed.
- Float money. Currency in IEEE 754 doubles, pennies drifting across aggregation, found at reconciliation.
- Silent rounding. The tool rounds half-even, the ledger rounds half-up, nobody declared either.
- Unbound operands. Numbers lifted off a document with no reference to a stored record: the computation is exact and the inputs are fiction.
- Formula drift. The model picks the wrong equation and the calculator executes it perfectly — the largest error class in MedCalc-Bench at 40%.
- Chain-of-thought as evidence. A reviewer signs off on working that never described the computation.
Diablo, the auditor I run across my own portfolio, checks seventeen production-readiness categories plus a first-party adversarial challenge stage; free-text arithmetic recurs in the findings.
The test predates every paper above. Can you rebuild the answer without calling the model? If not, you don't have a system. You have a demo with a try/except around it. For a figure on an invoice, the replay test separates a number you can defend from a number you can only apologise for.
Let the model read the messy document. Let it name the operation. Then get it out of the way and let code do the sum. Extract, compute, explain: the model names the operation and extracts the operands, deterministic code performs the arithmetic, the model explains a result it did not produce.