Why Your AI's Revenue Total Is Off by a Few Cents
Asked for total revenue and got $10,000.02 instead of $10,000.00 — or a percentage that doesn't quite reconcile. Money stored as FLOAT/DOUBLE can't represent cents exactly. SUM then makes the error visible.
You ask for last month's revenue. The AI returns $40,218.17. Finance has $40,218.00. You pull ten rows and add them by hand — they add up. The SQL has no extra join. The column is DOUBLE (or FLOAT / REAL), and those types cannot store 0.10 exactly.
Binary fractions vs cents
0.1 in binary floating point is a repeating approximation, the same reason 0.1 + 0.2 === 0.3 is false in JavaScript. A single row looks fine when you print two decimal places. SUM over tens of thousands of rows surfaces the leftover bits as a few cents (sometimes more).
-- looks like money, isn't exact
SELECT SUM(amount) FROM payments; -- amount is DOUBLE
-- exact cents
SELECT SUM(amount) FROM payments; -- amount is NUMERIC(12,2)
Same query text. Different type, different total. No error either way.
This is a small-error cousin of JOIN fan-out (totals that are multiples too high) and integer division (rates that collapse to 0). FLOAT drift is the one that looks almost right — which is why it survives a casual glance.
How to tell what you have
describe_table on the payments/orders table. If amount, price, total, or refund is real, float, float8, double, or double precision, you are in this bug. numeric, decimal, and money (Postgres) are the types that keep cents.
MySQL's FLOAT/DOUBLE vs DECIMAL is the same split. SQL Server: FLOAT/REAL vs DECIMAL/NUMERIC.
What to do in the query (when you can't change the column)
Cast before you add:
-- Postgres
SELECT SUM(amount::numeric(12,2)) FROM payments;
-- MySQL / SQL Server
SELECT SUM(CAST(amount AS DECIMAL(12,2))) FROM payments;
Still not a substitute for storing money as decimal. It does stop the SUM from adding binary dust to binary dust. If you need to reconcile to the cent, say so in the prompt and ask for the raw type first.
How to catch it
- Ask
describe_tablefor the money column's type - Re-run
SUMwith an explicit decimal cast - Compare both totals to a number you already trust (Stripe, the admin UI, last month's invoice)
A 2-cent gap that disappears after the cast is this. A 3× gap is still a join.
The prompt that heads this off
Before summing amount/price/total/refund, describe_table and check
the type. If it's FLOAT/REAL/DOUBLE, cast to NUMERIC/DECIMAL before
SUM and say so. Don't treat a 2-decimal printout as exact cents.
The short version
Two decimal places on the screen are not two decimal places in the column. If revenue is a few cents off and the SQL looks clean, read the type before you rewrite the join.
Read-only MCP gateway: mcpserver.design.
Related reading: