La gestione della precisione numerica è una pietra angolare della contabilità a partita doppia. Nella tenuta dei libri contabili digitali, specialmente quando si ha a che fare con più valute, prezzi di azioni e frazioni di azioni, piccole discrepanze di arrotondamento possono rapidamente portare a frustranti errori di bilanciamento. Beancount fornisce un sistema sofisticato ma intuitivo per gestire la precisione e impostare tolleranze accettabili. Questa guida ti accompagnerà attraverso il suo funzionamento. ⚙️
Ogni numero in questa pagina è stato verificato con Beancount 3.2.3, inclusi i valori limite: ogni esempio indica quale residuo viene accettato e quale supera la tolleranza di una cifra.
Concetti Fondamentali sulla Precisione
L'obiettivo primario di Beancount è garantire che ogni transazione sia bilanciata a zero. Tuttavia, i calcoli che coinvolgono prezzi o costi spesso producono risultati con più cifre decimali di quanto sia pratico registrare. Il sistema di tolleranza consente piccoli e accettabili squilibri.
Tolleranza Automatica
Per impostazione predefinita, Beancount deduce automaticamente la tolleranza necessaria per ogni transazione. Questa deduzione viene applicata singolarmente per ogni transazione e calcolata separatamente per ogni valuta coinvolta.
La regola è una moltiplicazione: la tolleranza per una valuta è la cifra più piccola osservata negli importi delle registrazioni in quella valuta, moltiplicata per l'opzione tolerance_multiplier, che per impostazione predefinita è 0.5. Con questa impostazione predefinita, la tolleranza è la metà dell'ultima cifra significativa.
Ad esempio, considera questo acquisto:
2013-04-03 * "Buy Fund"
Assets:Fund 10.22626 FUND {37.61 USD}
Assets:Cash -384.61 USDBeancount deduce le tolleranze come segue:
- Per la valuta
FUND, il numero10.22626ha 5 cifre decimali. La tolleranza è la metà dell'ultima cifra, quindi $0.00001 \div 2 = 0.000005$FUND. - Per la valuta
USD, il numero-384.61ha 2 cifre decimali. La tolleranza è la metà dell'ultima cifra, quindi $0.01 \div 2 = 0.005$USD.
Il valore in contanti è ciò contro cui viene misurata la tolleranza: 10.22626 × 37.61 è 384.6096386, quindi questa transazione ha un disavanzo di 0.0003614 USD rispetto allo zero e viene caricata. Se arrotondi la voce in contanti a -384.60, il divario diventa 0.0096386 USD, superando la tolleranza di 0.005, e Beancount segnala Transaction does not balance.
Regole per il Peso delle Registrazioni
Quando verifica se una transazione è bilanciata, Beancount calcola il "peso" di ogni registrazione. Le regole per questo calcolo sono:
- Importo Semplice: Se una registrazione ha solo un importo (es.,
Assets:Cash -100.00 USD), il suo peso è quell'importo esatto. - Registrazione con Prezzo: Se una registrazione ha un prezzo unitario (es.,
10 FUND @ 38.46 USD), il suo peso èamount × price. - Costo Unitario: Le parentesi graffe singole contengono il costo di una singola unità, quindi
10 FUND {384.61 USD}pesa10 × 384.61 = 3,846.10 USD, non384.61 USD. - Costo Totale: Le doppie parentesi graffe contengono il costo dell'intera registrazione, quindi
10 FUND {{384.61 USD}}pesa384.61 USD. Beancount lo converte in un costo unitario di38.461 USDquando lo memorizza. - Costo e Prezzo: Se una registrazione ha sia un costo che un prezzo unitario (es.,
10 FUND {384.61 USD} @ 400.00 USD), solo il costo viene utilizzato per il bilanciamento. Il prezzo viene registrato per il reporting, non per l'aritmetica.
Le regole 3 e 4 sono quelle che costano un pomeriggio di lavoro alle persone, quindi eccole affiancate in un file che viene caricato correttamente:
1970-01-01 open Assets:Fund
1970-01-01 open Assets:Cash
; Per-unit cost: ten units at 384.61 each, so 3,846.10 USD leaves the
; cash account.
2013-04-03 * "Broker" "Buy at a per-unit cost"
Assets:Fund 10 FUND {384.61 USD}
Assets:Cash -3846.10 USD
; Total cost: the braces double and 384.61 USD is the entire purchase.
; The lot is stored at 38.461 USD per unit.
2013-04-04 * "Broker" "Buy at a total cost"
Assets:Fund 10 FUND {{384.61 USD}}
Assets:Cash -384.61 USDIl conto termina con 20 FUND in due lotti, con 4,230.71 USD di costo totale tra loro.
Regole per la Deduzione della Precisione
Il sistema di deduzione automatica segue alcune regole specifiche:
- Formato del Numero
- Gli importi interi (es.,
10 USD) non contribuiscono alla deduzione della precisione. - Una cifra decimale è la precisione più grossolana che un importo può implicare:
0.1 × 0.5 = 0.05unità. Oltre a questo, hai bisogno ditolerance_multipliero di un'impostazione predefinita per valuta, come descritto di seguito. - Costi e prezzi (es.,
{37.61 USD}) sono esclusi dalla deduzione della tolleranza per impostazione predefinita. Vengono utilizzati solo gli importi primari delle registrazioni. - Se le registrazioni per la stessa valuta hanno precisioni diverse (es.,
-10.10 USDe5.123 USD), Beancount utilizza la tolleranza più grossolana (più grande). In questo caso, sarebbe basata su-10.10 USD, producendo una tolleranza di $0.005$USD.
-
Gestione dell'Impostazione Predefinita Puoi impostare una tolleranza predefinita globale o specifica per valuta se una transazione non ha numeri con cifre decimali da cui dedurla.
; 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" -
Moltiplicatore di Tolleranza L'opzione è
tolerance_multiplier, ed è la frazione dell'ultima cifra significativa che conta come tollerabile — non una percentuale aggiunta. Il suo valore predefinito è0.5, quindi impostandolo a1.2non si allentano i controlli del 20%: rende ogni tolleranza dedotta 2.4 volte quella predefinita.option "tolerance_multiplier" "1.2" 1970-01-01 open Assets:Cash 1970-01-01 open Expenses:Fees ; The coarsest amount has two decimals, so the tolerance is ; 1.2 x 0.01 = 0.012 USD, and this residual of exactly 0.012 passes. ; At the default 0.5 the tolerance would be 0.005 and this would fail. 2024-05-01 * "Bank" "Wire fee" Expenses:Fees 100.00 USD Assets:Cash -99.988 USDIl nome più vecchio
inferred_tolerance_multiplierimposta lo stesso valore, ma segnalaRenamed to 'tolerance_multiplier'.come errore di caricamento. -
Deduzione Basata sul Costo Sebbene i costi siano normalmente ignorati per la deduzione della tolleranza, puoi istruire Beancount a utilizzarli. Questo è utile quando l'importo finale (es., un prelievo di contante) è il numero più preciso in una transazione.
option "infer_tolerance_from_cost" "TRUE"
Ecco l'impostazione predefinita semplice, senza opzioni aggiuntive, al suo esatto valore limite:
1970-01-01 open Assets:Cash
1970-01-01 open Expenses:Fees
; Two decimals on the coarsest amount, so the tolerance is
; 0.5 x 0.01 = 0.005 USD. This residual is exactly 0.005 and passes;
; -99.994 would be 0.006 and would fail.
2024-05-01 * "Bank" "Wire fee"
Expenses:Fees 100.00 USD
Assets:Cash -99.995 USDAsserzioni di Bilancio
Le asserzioni di bilancio (balance) vengono utilizzate per verificare che il saldo di un conto corrisponda a un valore noto in una data specifica. Anch'esse hanno una tolleranza associata.
Formato di Base
La tolleranza per un'asserzione di balance viene dedotta dal numero di cifre decimali dell'importo, ma è due volte più generosa di quella usata all'interno di una transazione: tolerance_multiplier × 2 × the smallest digit. Con il moltiplicatore predefinito, corrisponde esattamente a un'unità dell'ultima cifra decimale che hai scritto.
; Asserts the balance is 4.271 RGAGX with a tolerance of +/-0.001
2015-05-08 balance Assets:Fund 4.271 RGAGX
; Asserts the balance is 4.27 RGAGX with a tolerance of +/-0.01
2015-05-08 balance Assets:Fund 4.27 RGAGXIl confronto è inclusivo: una differenza esattamente uguale alla tolleranza supera comunque il controllo. Per il secondo esempio, qualsiasi saldo da $4.26$ a $4.28$ supera il controllo, mentre 4.2801 fallisce con Balance failed for 'Assets:Fund': expected 4.27 RGAGX != accumulated 4.2801 RGAGX (0.0101 too much).
1970-01-01 open Assets:Fund
1970-01-01 open Equity:Opening-Balances
1970-01-02 * "Broker" "Opening position"
Assets:Fund 4.28 RGAGX
Equity:Opening-Balances -4.28 RGAGX
; 4.28 is 0.01 away from the asserted 4.27, which is the whole tolerance.
2015-05-08 balance Assets:Fund 4.27 RGAGXTolleranze Esplicite
Se la tolleranza dedotta non è adatta, puoi specificarne una esplicitamente usando il carattere tilde (~). Questa è l'unica sintassi per tolleranze esplicite in Beancount e funziona solo con le direttive balance — una tilde all'interno di una registrazione di transazione è un errore di sintassi.
1970-01-01 open Assets:Fund
1970-01-01 open Equity:Opening-Balances
1970-01-02 * "Broker" "Opening position"
Assets:Fund 4.281 RGAGX
Equity:Opening-Balances -4.281 RGAGX
; Asserts the balance is 4.271 RGAGX with a custom tolerance of
; +/-0.01 RGAGX, so anything from 4.261 to 4.281 passes.
2015-05-08 balance Assets:Fund 4.271 ~ 0.01 RGAGXPorta il saldo a 4.2811 e la stessa asserzione fallisce di 0.0101.
Gestione dell'Arrotondamento
Piccoli residui derivanti dall'aritmetica di costi e prezzi sono normali. Ciò che Beancount fa con essi è più limitato di quanto sembri.
Tracciamento degli Errori di Arrotondamento
L'opzione account_rounding nomina un conto destinato ad assorbire i residui. Accetta un nome di conto completo e viene memorizzato esattamente come lo scrivi — non viene aggiunto alcun prefisso relativo al patrimonio netto, a differenza delle opzioni per i conti di patrimonio netto.
option "account_rounding" "Equity:Rounding"
1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
; 1.245 x 43.23 = 53.82135, so this is 0.00135 USD short of balancing.
2013-02-23 * "Broker" "Purchase"
Assets:Invest 1.245 RGAGX {43.23 USD}
Assets:Cash -53.82 USDIn questa transazione, . La transazione è sbilanciata di $-0.00135$ USD, che rientra nella tolleranza dedotta di 0.005 USD, quindi viene caricata.
Su Beancount 3.2.3 non viene registrato nulla su Equity:Rounding. L'opzione viene analizzata e memorizzata, ma nessuna fase del caricatore inserisce la registrazione residua, quindi il conto termina a zero e un residuo che è fuori tolleranza è comunque un errore piuttosto che essere spazzato via:
option "account_rounding" "Equity:Rounding"
1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
; 0.10135 USD out, far past the 0.005 tolerance. Setting
; account_rounding does not rescue it:
; Transaction does not balance: (0.10135 USD)
2013-02-23 * "Broker" "Purchase"
Assets:Invest 1.245 RGAGX {43.23 USD}
Assets:Cash -53.72 USDQuindi tratta account_rounding come inerte su questa versione. Se vuoi che un residuo venga registrato piuttosto che tollerato, scrivi tu stesso la terza registrazione:
1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
2013-02-23 * "Broker" "Purchase"
Assets:Invest 1.245 RGAGX {43.23 USD}
Assets:Cash -53.82 USD
Equity:Rounding -0.00135 USDQuella versione si bilancia esattamente a zero e la polvere è visibile in un conto su cui puoi fare report.
Precisione Numerica Dedotta
Beancount non arrotonda i numeri che scrivi. Non esiste un'opzione default_tolerance — non esiste e fallisce il caricamento con Invalid option: 'default_tolerance' — e nessuna impostazione quantizza gli importi memorizzati.
-
La memorizzazione è sempre esatta. Scrivi
53.82135 USDe il registro contiene53.82135 USD, qualunque cosa dicano le tue impostazioni di tolleranza. La tolleranza decide se una transazione è accettata; non modifica mai un numero. -
La visualizzazione è un'impostazione separata.
display_precisionfissa quante cifre frazionarie vengono visualizzate per una valuta e non cambia nulla riguardo al valore memorizzato o al controllo del saldo.option "display_precision" "USD:0.01" 1970-01-01 open Assets:Cash 1970-01-01 open Income:Interest ; Rendered as 53.82 USD, stored as 53.82135 USD. 2024-06-30 * "Bank" "Interest" Assets:Cash 53.82135 USD Income:Interest -53.82135 USD -
L'arrotondamento è una registrazione che scrivi tu. Se vuoi eliminare il residuo dall'aritmetica, arrotonda l'importo nella fonte e registra la differenza esplicitamente, come nell'esempio con tre registrazioni sopra.
Dettagli Implementativi
Alcuni punti tecnici chiariscono come Beancount raggiunge questa affidabilità.
-
Rappresentazione dei Numeri: Beancount utilizza il modulo
decimaldi Python, non numeri a virgola mobile. Il contesto predefinito porta 28 cifre significative — cifre totali, non cifre dopo il punto decimale — il che evita gli errori di rappresentazione binaria comuni ai float. -
Classe DisplayContext: Questa classe interna gestisce tutta la formattazione dei numeri per scopi di visualizzazione. Deduce la precisione di ciascuna valuta dai numeri nel tuo file a meno che
display_precisionnon la fissi, e può formattare l'output con colonne allineate e virgole. -
Precisione vs. Tolleranza: È fondamentale distinguere questi due concetti:
- La Precisione riguarda il formato di visualizzazione di un numero (quante cifre decimali vengono mostrate).
- La Tolleranza è il margine consentito per lo squilibrio utilizzato durante i controlli di verifica.
Buone Pratiche ✨
Ecco alcuni consigli pratici per gestire la precisione nel tuo registro.
Configurazione Iniziale
Per la maggior parte dei nuovi registri, questa è una configurazione iniziale robusta:
; A floor for currencies that have no decimals to infer from
option "inferred_tolerance_default" "*:0.005"
; Leave the multiplier at its 0.5 default unless a real institution
; forces your hand; 1.2 would mean 2.4x the usual tolerance.
option "tolerance_multiplier" "0.5"Suggerimenti per la Risoluzione dei Problemi
Se incontri errori di bilanciamento:
- Aggiungi cifre decimali all'importo di una registrazione per creare una deduzione della tolleranza locale più precisa e accurata.
- Usa tolleranze esplicite (
~) sulle asserzioni dibalanceche falliscono a causa di discrepanze prevedibili. - Registra il residuo su un conto dedicato con una vera terza registrazione, così puoi fare report su quanto spesso accade.
- Considera l'impostazione di valori predefiniti specifici per valuta se hai spesso a che fare con valute che hanno convenzioni diverse (es., JPY non ha decimali).
Strategia di Migrazione
Quando applichi questi concetti a un registro esistente e disordinato:
- Inizia con una tolleranza globale generosa (es.,
*:0.05) e untolerance_multiplierpiù alto per far validare il file. - Progressivamente restringi le tolleranze e correggi gli errori che emergono.
- Aggiungi cifre esplicite agli importi nelle transazioni problematiche per permettere alla deduzione di fare il suo lavoro.
- Monitora il saldo del conto di arrotondamento. Un saldo grande o in rapida crescita può segnalare un problema sistemico che richiede indagine.