A Guide to Precision & Tolerances in Beancount
Managing numerical precision is a cornerstone of double-entry accounting. In digital bookkeeping, especially when dealing with multiple currencies, stock prices, and fractional shares, small rounding discrepancies can quickly lead to frustrating balancing errors. Beancount provides a sophisticated but intuitive system for handling precision and setting acceptable tolerances. This guide will walk you through how it works. ⚙️
Core Precision Concepts
Beancount's primary goal is to ensure that every transaction balances to zero. However, calculations involving prices or costs often produce results with more decimal places than are practical to record. The tolerance system allows for small, acceptable imbalances.
Automatic Tolerance Inference
By default, Beancount infers the required tolerance for each transaction automatically. This inference is handled individually for every transaction and calculated separately for each currency involved.
The rule is simple: the tolerance is half of the last significant digit of the numbers present in the transaction's postings.
For example, consider this purchase:
2013-04-03 * "Buy Fund"
Assets:Fund 10.22626 FUND {37.61 USD}
Assets:Cash -384.61 USD
Beancount infers the tolerances as follows:
- For the
FUND
commodity, the number10.22626
has 5 decimal places. The tolerance is half of the last digit, soFUND
. - For the
USD
commodity, the number-384.61
has 2 decimal places. The tolerance is half of the last digit, soUSD
.
Transaction Weight Rules
When checking if a transaction balances, Beancount calculates the "weight" of each posting. The rules for this calculation are:
- Simple Amount: If a posting has only an amount (e.g.,
Assets:Cash -100.00 USD
), its weight is that exact amount. - Price Posting: If a posting has a per-unit price (e.g.,
10 FUND @ 38.46 USD
), its weight is theamount × price
. - Cost Posting: If a posting has a total cost (e.g.,
10 FUND {384.61 USD}
), its weight is the total cost amount. - Cost and Price: If a posting has both a total cost and a per-unit price (e.g.,
10 FUND {384.61 USD} @ 38.46 USD
), only the total cost is used for balancing. The per-unit price is treated as a comment or memo.
Precision Inference Rules
The automatic inference system follows a few specific rules:
- Number Format
- Integer amounts (e.g.,
10 USD
) do not contribute to precision inference. - The maximum tolerance that can be automatically inferred is
0.05
units (e.g., from a number like10.1 USD
). If you need a larger tolerance, you must specify it manually. - Costs and prices (e.g.,
{37.61 USD}
) are excluded from tolerance inference. Only the primary amounts of the postings are used. - If postings for the same currency have different precisions (e.g.,
-10.10 USD
and5.123 USD
), Beancount uses the coarsest (largest) tolerance. In this case, it would be based on-10.10 USD
, yielding a tolerance ofUSD
.
-
Default Handling You can set a global or currency-specific default tolerance if a transaction has no numbers with decimal places from which to infer it.
; Sets a default tolerance for all currencies without explicit rules
option "inferred_tolerance_default" "*:0.001"
; Sets a specific default tolerance for USD
option "inferred_tolerance_default" "USD:0.003" -
Tolerance Multiplier You can globally increase all inferred tolerances by a fixed multiplier. This is useful for loosening checks across your entire file without changing every transaction. A multiplier of
1.2
increases all inferred tolerances by 20%.option "inferred_tolerance_multiplier" "1.2"
-
Cost-Based Inference While costs are normally ignored for tolerance inference, you can instruct Beancount to use them. This is helpful when the final amount (e.g., a cash withdrawal) is the most precise number in a transaction.
option "infer_tolerance_from_cost" "TRUE"
Balance Assertions
Balance assertions (balance
) are used to verify that your account's balance matches a known value on a specific date. They also have an associated tolerance.
Basic Format
Similar to transactions, the tolerance for a balance
assertion is inferred from the number of decimal places in the amount.
; Asserts the balance is 4.271 RGAGX with a tolerance of ±0.0005
2015-05-08 balance Assets:Fund 4.271 RGAGX
; Asserts the balance is 4.27 RGAGX with a tolerance of ±0.005
2015-05-08 balance Assets:Fund 4.27 RGAGX
The calculated balance must fall within this range. For the second example, any balance between and would pass the check.