Reconciliation is off by a few cents and every line item checks out—should I check field types or allocation logic first?
When finance sends the reconciliation statement back and says the system total is off by a few cents from the sum of line items, the likely cause is not that someone calculated wrong, but that the same amount uses inconsistent numeric representations across the three layers of storage, computation, and presentation. Based on common 2026 delivery experience, if any one layer carries amounts in binary floating point (float/double), deviations on the order of 0.01 will appear after several rounds of discounts, allocations, and summation; a single transaction may not reveal it, and it only becomes visible when hundreds or thousands of rows are aggregated. The starting point should be to confirm whether the field type, backend numeric type, and frontend formatting are aligned, then confirm whether rounding rules and residual attribution are fixed in an agreed convention—do not start by changing code.
Why do a few cents appear out of nowhere?
Binary floating point uses a finite number of bits to approximate decimal fractions; 0.1 is a repeating fraction in binary, so the moment it is written it is already not 0.1. For a single transaction this error is at a very small magnitude and seems irrelevant; but amounts come from accumulation: an order contains unit price times quantity, proportional discount allocation, tax rates, and multi-line subtotals, so the error grows with the number of operations and rows. The typical range is: almost invisible for a single transaction, but when aggregated to thousands of detail rows the difference falls between 0.01 and 0.1 yuan, exactly enough for finance to send the statement back.
Amounts are not ordinary numbers; they have an explicit requirement that the sum of details must equal the total, and refunds, transaction records, and invoices must reconcile with one another. Therefore their acceptance criteria differ from ordinary fields: you should recalculate through a different data retrieval path and confirm the result is still consistent, rather than simply retrieving it and considering it passed because it looks right.
- Unit price, quantity, discount, tax amount, allocated amount—if any step falls on floating point it introduces deviation, and the later it appears the harder it is to trace.
- If proportional allocation does not define rounding rules and residual attribution, a one-cent difference is inevitable; only the row where it lands is random.
- Storing decimal in the database but receiving it as double in the program also loses precision—precision is a property of the whole chain, not of a single field.
Check field types first or allocation logic first: verify through three layers
The recommended order is: first look at the storage layer's field types, then the computation layer's numeric types and rounding, and finally the presentation layer's formatting. The reason is practical: the storage layer is the only place you can see everything at once—checking the table schema or metadata makes it clear; conversely, starting from page styles can easily cover the problem in the presentation layer while computation-layer deviations continue to accumulate.
- Storage layer: Check whether field types are decimal/numeric or integer cents; check for implicit conversions in JOINs, views, and ETL; and confirm whether exported reports go through another read path.
- Computation layer: Check the language and framework's numeric types (e.g., whether high-precision numeric types are constructed from strings, and whether the ORM maps decimal to double), rounding rules (round half up or banker's rounding), and residual attribution.
- Presentation layer: Check whether the frontend uses Number to calculate amounts directly, whether thousands separators and two decimal places are applied only in the final step, and whether the API sends strings or floating-point values.
The caveat with three-layer verification is that changes often need to be made in two or three layers together; changing only one layer just moves the problem elsewhere. An experience-based practice is to replay and compare a segment of historical detail after the change, and only pass if the difference between the old and new paths is 0, rather than sampling a few orders and calling it close enough.
Floating point, decimal, and integer cents: cost comparison of three storage approaches
Which one to choose is not a matter of taste; it depends on the amount range, whether there are allocations and exchange rates, and the migration cost the team can bear. A common situation in projects is: a new table casually uses double, and only when settlement statements need to be produced does the team discover that the whole chain has to be changed retroactively.
- Binary floating point (float/double): Fast computation and small storage, but decimal fractions are inexact. Suitable for statistical and non-accounting metric estimates; not suitable for any amount that needs reconciliation.
- Fixed-point decimal (decimal/numeric, commonly scale 2, or 4–6 for exchange rates): Semantics fit accounting, and databases and most languages have native support. The cost is slower computation than integers, and across languages you need to watch precision limits and ORM mapping.
- Integer storage in the smallest unit (e.g., integer cents): Addition and subtraction are exact and it is the most stable across languages. The cost is that all input and output require a unit conversion, and proportional allocation should explicitly define rounding rules.
For cost, here is a checkable experience range: for a new project choosing decimal or integer cents from scratch, the extra cost is basically zero—you only write one or two conversion utility methods; for a running system that needs field type changes, it involves data migration, dual-write comparison, and downstream report regression, typically taking 1–3 weeks, and the more tables and report dependencies there are, the closer it is to the upper limit. For systems with many cross-client calls (mini-programs, apps, and reporting tools all read the API directly), integer cents is easier; for systems mainly doing in-database computation and writing many report SQL queries, decimal is more convenient.
Delivery scene: a two-day window and no table changes—how to keep the difference under control
Once, only two days were budgeted for investigation, historical orders had been in the database for three months, the table schema could not be changed, and three downstream reports read directly from that table. The approach was to first add a high-precision shadow field and run dual writes, with new data written in parallel to both sets; meanwhile, extract the rounding and residual attribution in the allocation logic into a shared method called by both entry points. After two weeks, the difference was narrowed down to an incorrect rounding position in tiered discounts, not the database field itself. The cost was also concrete: new data became clean, but historical accounts already written in floating point still required a manual review round—estimated at two to three person-days by typical range—which is the bill for not getting types right first.
Where this applies and where it does not
Not every place with decimals needs accounting precision. The criterion is simple: will this number be used for reconciliation, invoicing, settlement, or refunds? If yes, follow the approach above; if not, do not over-engineer—otherwise using decimal even for a rating field slows writes and adds conversion bugs.
- Should use accounting precision: order amounts, refunds, settlement statements, invoices, revenue sharing, points conversion, and reports that have a detail-to-total relationship and require three-way reconciliation.
- No need to copy this approach: display metrics (ratings, temperature, progress, percentage estimates), duration ratios in tracking and logs, and intermediate values that are calculated once and discarded without accumulation.
In other words, the level of amount precision required is proportional to whether this money may need to be explained down to the cent.
Frequently asked questions
If the database field is clearly decimal, why does the program still calculate a deviation?
decimal only guarantees exact storage; if it is retrieved and mapped to floating point, or multiplication/division is done on floating point, precision is still lost. Log the actual type at each of the storage, computation, and presentation layers once, then decide.
If only one or two APIs do not reconcile, should the whole database change field types?
In most cases no. First locate which segment the deviation appears in; it commonly falls in the computation or formatting step. If the table really must be changed, dual-write comparison is recommended first, and the scope is usually much smaller than a whole-database migration.
The amount shown on the page differs by one cent from the backend export—which side should be changed first?
First confirm whether both sides retrieve the same detail records and whether rounding is done in the same place. A common cause is that the export side calculates again on the client side; first consolidate the calculation on the server side.
Which line item should carry the residual generated by discount allocation?
An experience-based practice is to define it explicitly—for example, assign it to the last line or the line with the largest amount—and write it into the acceptance criteria. Without an agreement, a one-cent difference will land randomly on some row and be hard to explain afterward.
If we switch to integer cents, do we no longer need to worry about rounding?
Addition and subtraction are indeed exact, but proportional allocation and exchange-rate conversion still require rounding rules and residual attribution, and places that convert units on input and output can easily miss multiplying by 100, so regression verification is still needed.
If you are currently stuck on a reconciliation that is off by a few cents, start with one small step: take a batch of known detail records and log the actual numeric type at each of the storage, computation, and presentation layers; most breakpoints will show up directly. For systems that have been running for a while and have large historical data volumes, assess the migration cost before acting—do not trigger a full regression for a few cents. The above approach applies to accounting amounts with reconciliation requirements; display values do not need to copy it.
-
Large form submit takes two minutes, then returns login expired: renew in advance or wait for a 401?
Date: Nov 12, 2026 Read: 10
-
After a password reset, the old phone can still sign in—does that mean the reset failed?
Date: Nov 11, 2026 Read: 16
-
Old build hits “column does not exist” on the new database during rollback—can we just restore a backup to roll the database back?
Date: Nov 10, 2026 Read: 17
-
Same Query Is Fast in the Morning but Slow in the Afternoon: Check the Execution Plan or Lock Waits First?
Date: Nov 9, 2026 Read: 22
-
Contract attachment previews after upload but another machine says the file does not exist the next day: check storage location or download API first?
Date: Nov 8, 2026 Read: 19




