Preskočiť na hlavný obsah

Presnosť a tolerancie

Naučte sa, ako systémy presnosti a tolerancií v Beancount pomáhajú udržiavať rovnováhu v podvojnom účtovníctve, najmä pri zložitých transakciách zahŕňajúcich viacero mien a zlomkové hodnoty.

Riadenie numerickej presnosti je základom podvojného účtovníctva. V digitálnom účtovníctve, najmä pri práci s viacerými menami, cenami akcií a zlomkovými podielmi, môžu malé rozdiely zo zaokrúhľovania rýchlo viesť k frustrujúcim chybám pri vyrovnávaní. Beancount poskytuje sofistikovaný, ale intuitívny systém na spracovanie presnosti a nastavenie prijateľných tolerancií. Tento sprievodca vás prevedie tým, ako funguje. ⚙️

Každé číslo na tejto stránke bolo overené proti Beancount 3.2.3, vrátane hraničných hodnôt: každý príklad uvádza, ktorý zvyšok je akceptovaný a ktorý je o jednu číslicu príliš ďaleko.

Základné koncepty presnosti

Primárnym cieľom Beancount je zabezpečiť, aby každá transakcia bola vyrovnaná na nulu. Avšak výpočty zahŕňajúce ceny alebo náklady často produkujú výsledky s väčším počtom desatinných miest, než je praktické zaznamenať. Systém tolerancií umožňuje malé, prijateľné nevyrovnanosti.

Automatická inferencia tolerancií

Beancount štandardne odvodzuje požadovanú toleranciu pre každú transakciu automaticky. Táto inferencia sa vykonáva individuálne pre každú transakciu a vypočítava sa samostatne pre každú zúčastnenú menu.

Pravidlo je jedno násobenie: tolerancia pre menu je najmenšia číslica videná v sumách položiek tejto meny, vynásobená možnosťou tolerance_multiplier, ktorá je štandardne 0.5. Pri tomto štandarde je tolerancia polovica poslednej významnej číslice.

Napríklad, zvážte tento nákup:

2013-04-03 * "Buy Fund"
  Assets:Fund     10.22626 FUND {37.61 USD}
  Assets:Cash     -384.61 USD

Beancount odvodí tolerancie takto:

  • Pre komoditu FUND, číslo 10.22626 má 5 desatinných miest. Tolerancia je polovica poslednej číslice, takže $0.00001 \div 2 = 0.000005$ FUND.
  • Pre menu USD, číslo -384.61 má 2 desatinné miesta. Tolerancia je polovica poslednej číslice, takže $0.01 \div 2 = 0.005$ USD.

Hotovostná časť je to, proti čomu sa tolerancia meria: 10.22626 × 37.61 je 384.6096386, takže táto transakcia je 0.0003614 USD od nuly a načíta sa. Zaokrúhlite hotovostnú časť na -384.60 a rozdiel sa stane 0.0096386 USD, čo presahuje toleranciu 0.005, a Beancount hlási Transaction does not balance.

Pravidlá pre váhu transakcie

Pri kontrole, či je transakcia vyrovnaná, Beancount vypočítava "váhu" každej položky. Pravidlá pre tento výpočet sú:

  1. Jednoduchá suma: Ak má položka iba sumu (napr. Assets:Cash -100.00 USD), jej váha je presne táto suma.
  2. Položka s cenou: Ak má položka cenu za jednotku (napr. 10 FUND @ 38.46 USD), jej váha je amount × price.
  3. Náklad za jednotku: Jednoduché zložené zátvorky držia náklad jednej jednotky, takže 10 FUND {384.61 USD} váži 10 × 384.61 = 3,846.10 USD, nie 384.61 USD.
  4. Celkový náklad: Dvojité zložené zátvorky držia náklad celej položky, takže 10 FUND {{384.61 USD}} váži 384.61 USD. Beancount to prevedie na náklad za jednotku 38.461 USD, keď ukladá dávku.
  5. Náklad a cena: Ak má položka aj náklad, aj cenu za jednotku (napr. 10 FUND {384.61 USD} @ 400.00 USD), iba náklad sa použije na vyrovnanie. Cena sa zaznamenáva pre výkazníctvo, nie pre aritmetiku.

Pravidlá 3 a 4 sú tie, ktoré ľuďom zaberú popoludnie, takže tu sú vedľa seba v súbore, ktorý sa načíta:

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 USD

Účet končí s 20 FUND v dvoch dávkach, s 4,230.71 USD nákladovej základne medzi nimi.

Pravidlá inferencie presnosti

Automatický inferenčný systém sa riadi niekoľkými konkrétnymi pravidlami:

  1. Formát čísla
  • Celé sumy (napr. 10 USD) neprispievajú k inferencii presnosti.
  • Jedno desatinné miesto je najhrubšie, čo suma môže naznačovať: 0.1 × 0.5 = 0.05 jednotiek. Nad to potrebujete tolerance_multiplier alebo predvolenú hodnotu pre menu, oboje nižšie.
  • Náklady a ceny (napr. {37.61 USD}) sú vylúčené z inferencie tolerancií štandardne. Používajú sa iba primárne sumy položiek.
  • Ak majú položky pre rovnakú menu rôznu presnosť (napr. -10.10 USD a 5.123 USD), Beancount použije najhrubšiu (najväčšiu) toleranciu. V tomto prípade by bola založená na -10.10 USD, čo dáva toleranciu $0.005$ USD.
  1. Predvolené spracovanie Môžete nastaviť globálnu alebo pre menu špecifickú predvolenú toleranciu, ak transakcia nemá žiadne čísla s desatinnými miestami, z ktorých by sa dala odvodiť.

    ; 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"
  2. Multiplikátor tolerancie Možnosť je tolerance_multiplier a je to zlomok najmenšej číslice, ktorý sa považuje za tolerovateľný — nie percento pridané navrch. Jeho predvolená hodnota je 0.5, takže nastavenie 1.2 neuvoľní kontroly o 20%: spôsobí, že každá odvodená tolerancia bude 2.4-krát väčšia ako predvolená.

    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 USD

    Starší názov inferred_tolerance_multiplier nastavuje rovnakú hodnotu, ale hlási Renamed to 'tolerance_multiplier'. ako chybu načítania.

  3. Inferencia založená na nákladoch Zatiaľ čo náklady sú normálne ignorované pre inferenciu tolerancií, môžete Beancount inštruovať, aby ich použil. To je užitočné, keď je konečná suma (napr. výber hotovosti) najpresnejším číslom v transakcii.

    option "infer_tolerance_from_cost" "TRUE"

Tu je obyčajná predvolená hodnota, bez akýchkoľvek možností, na jej presnej hranici:

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 USD

Kontroly zostatkov

Kontroly zostatkov (balance) sa používajú na overenie, že zostatok vášho účtu zodpovedá známej hodnote k určitému dátumu. Majú tiež súvisiacu toleranciu.

Základný formát

Tolerancia pre kontrolu balance sa odvodzuje z počtu desatinných miest v sume, ale je dvakrát veľkorysejšia ako tá použitá v transakcii: tolerance_multiplier × 2 × the smallest digit. Pri predvolenom multiplikátore je to presne jedna jednotka posledného desatinného miesta, ktoré ste napísali.

; 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 RGAGX

Porovnanie je inkluzívne: rozdiel presne rovný tolerancii stále prejde. Pre druhý príklad, akýkoľvek zostatok od $4.26$ do $4.28$ prejde kontrolou a 4.2801 zlyhá s 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 RGAGX

Explicitné tolerancie

Ak odvodená tolerancia nie je vhodná, môžete explicitne zadať jednu pomocou znaku tilda (~). Toto je jediná syntax explicitnej tolerancie, ktorú Beancount má, a funguje iba na direktívach balance — tilda v rámci transakčnej položky je syntaktická chyba.

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 RGAGX

Posuňte držbu na 4.2811 a rovnaká kontrola zlyhá o 0.0101.

Riadenie zaokrúhľovania

Malé zvyšky z aritmetiky nákladov a cien sú normálne. To, čo s nimi Beancount robí, je užšie, než sa zdá.

Sledovanie chýb zaokrúhľovania

Možnosť account_rounding pomenúva účet určený na absorbovanie zvyškov. Vyžaduje úplný názov účtu a ukladá sa presne tak, ako ho napíšete — nepridáva sa žiadna predpona equity, na rozdiel od možností účtov equity.

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 USD

V tejto transakcii, $1.245 \times 43.23 = 53.82135$. Transakcia je nevyrovnaná o $-0.00135$ USD, čo je v rámci odvodenej tolerancie 0.005 USD, takže sa načíta.

Na Beancount 3.2.3 sa nič neúčtuje na Equity:Rounding. Možnosť sa analyzuje a uloží, ale žiadna fáza načítača nevkladá zvyškovú položku, takže účet končí na nule a zvyšok, ktorý je mimo tolerancie, je stále chybou, nie je zachytený:

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 USD

Takže považujte account_rounding za neaktívny na tejto verzii. Ak chcete, aby bol zvyšok zaznamenaný, nie tolerovaný, napíšte tretiu položku sami:

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 USD

Táto verzia sa vyrovná presne na nulu a prach je viditeľný v účte, o ktorom môžete podávať správy.

Odvodená presnosť čísel

Beancount nezaokrúhľuje čísla, ktoré píšete. Neexistuje žiadna možnosť default_tolerance — neexistuje a zlyhá načítanie s Invalid option: 'default_tolerance' — a žiadne nastavenie nekvantizuje uložené sumy.

  1. Ukladanie je vždy presné. Napíšte 53.82135 USD a účtovná kniha drží 53.82135 USD, nech už vaše nastavenia tolerancií hovoria čokoľvek. Tolerancia rozhoduje, či je transakcia prijatá; nikdy neupravuje číslo.

  2. Zobrazenie je samostatné nastavenie. display_precision určuje, s koľkými zlomkovými číslicami sa mena zobrazuje, a nič nemení na uloženej hodnote ani na kontrole zostatku.

    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
  3. Zaokrúhľovanie je vaša položka, ktorú treba napísať. Ak chcete zvyšok von z aritmetiky, zaokrúhlite sumu v zdroji a zaúčtujte rozdiel explicitne, ako v príklade s tromi položkami vyššie.

Detaily implementácie

Niekoľko technických bodov objasňuje, ako Beancount dosahuje túto spoľahlivosť.

  1. Reprezentácia čísel: Beancount používa Python modul decimal, nie čísla s pohyblivou rádovou čiarkou. Predvolený kontext nesie 28 významných číslic — celkových číslic, nie číslic za desatinnou čiarkou — čo sa vyhýba chybám binárnej reprezentácie bežným pri floatoch.

  2. Trieda DisplayContext: Táto interná trieda spracováva všetko formátovanie čísel na účely zobrazenia. Odvodzuje presnosť každej meny z čísel vo vašom súbore, pokiaľ display_precision ju nepripne, a môže formátovať výstup so zarovnanými stĺpcami a čiarkami.

  3. Presnosť vs. tolerancia: Je kľúčové rozlišovať tieto dva koncepty:

  • Presnosť sa vzťahuje na formát zobrazenia čísla (koľko desatinných miest sa zobrazuje).
  • Tolerancia je povolená odchýlka od rovnováhy používaná počas kontrol overovania.

Najlepšie postupy ✨

Tu je niekoľko praktických odporúčaní na riadenie presnosti vo vašej účtovnej knihe.

Počiatočné nastavenie

Pre väčšinu nových účtovných kníh je toto robustná počiatočná konfigurácia:

; 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"

Tipy na riešenie problémov

Ak narazíte na chyby vyrovnania:

  • Pridajte desatinné číslice do sumy položky, aby ste vytvorili užšiu, presnejšiu lokálnu inferenciu tolerancie.
  • Použite explicitné tolerancie (~) na kontrolách balance, ktoré zlyhávajú kvôli predvídateľným rozdielom.
  • Zaúčtujte zvyšok na vyhradený účet so skutočnou treťou položkou, aby ste mohli podávať správy o tom, ako často sa to stáva.
  • Zvážte nastavenie predvolených hodnôt pre konkrétne meny, ak často pracujete s menami, ktoré majú rôzne konvencie (napr. JPY nemá desatinné miesta).

Migračná stratégia

Pri aplikovaní týchto konceptov na existujúcu, neprehľadnú účtovnú knihu:

  1. Začnite s veľkorysou globálnou toleranciou (napr. *:0.05) a vyšším tolerance_multiplier, aby sa súbor validoval.
  2. Postupne sprísňujte tolerancie a opravujte chyby, ktoré sa objavia.
  3. Pridajte explicitné číslice do súm v problematických transakciách, aby inferencia mohla robiť svoju prácu.
  4. Sledujte zostatok účtu zaokrúhľovania. Veľký alebo rýchlo rastúci zostatok môže signalizovať systémový problém, ktorý si vyžaduje vyšetrenie.

Zdroj: https://beancount.io/sk/docs/Basics/precision