Skip to content

Commit

Permalink
Deployed b685439 with MkDocs version: 1.2.4
Browse files Browse the repository at this point in the history
  • Loading branch information
xuhcc committed Oct 1, 2024
1 parent 287a72c commit 43bcede
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 73 deletions.
4 changes: 2 additions & 2 deletions a_comparison_of_beancount_and_ledger_hledger.html
Original file line number Diff line number Diff line change
Expand Up @@ -359,15 +359,15 @@ <h3 id="numbers-and-precision-of-operations">Numbers and Precision of Operations
<p>Beancount, Ledger and HLedger all differ in how they represent their numbers internally, and in how they handle the precision of balance checks for a transaction’s postings.</p>
<p>First, about how number are represented: Ledger <a href="http://www.ledger-cli.org/3.0/doc/ledger3.html#Internal-Design"><u>uses rational numbers</u></a> in an attempt to maintain the full precision of numbers resulting from mathematical operations. This works, but <a href="https://groups.google.com/d/msg/ledger-cli/m-TgILbfrwA/YjkmOM3LHXIJ"><u>I believe this is perhaps not the most appropriate choice</u></a>. The great majority of the cases where operations occur involve the conversion from a number of units and a price or a cost to the total value of an account’s posted change (e.g., units x cost = total cost). Our task in representing transactional information is the replication of operations that take place mostly in institutions. These operations always involve the rounding of numbers for units and currencies (banks do apply stochastic rounding), and the <em>correct</em> numbers to be used from the perspective of these institutions, and from the perspective of the government, are indeed the <em>rounded</em> numbers themselves. It is a not a question of mathematical purity, but one of practicality, and our system should do the same that banks do. Therefore, I think that we should always post the rounded numbers to accounts. Using rational numbers is not a limitation in that sense, but we must be careful to store rounded numbers where it matters. I think the approach implemented by Ledger is to keep as much of the original precision as possible.</p>
<p>Beancount chooses a <a href="https://docs.python.org/3/library/decimal.html"><u>decimal</u></a> number representation to store the numbers parsed from the input with the same precision they are written as. This method suffers from the same problem as using rational numbers does in that the result of mathematical operations between the decimal numbers will currently be stored with their full precision (albeit in decimal). Admittedly, I have yet to apply explicit quantization where required, which would be the correct thing to do. A scheme has to be devised to infer suitable precisions for automatically quantizing the numbers after operations. The decimal representation provides natural opportunities for rounding after operations, and it is a suitable choice for this, implementations even typically provide a context for the precision to take place. Also note that it will never be required to store numbers to an infinite precision: the institutions never do it themselves.</p>
<p>HLedger, oddly enough, <a href="https://groups.google.com/d/msg/ledger-cli/m-TgILbfrwA/iZAv6IK3KuYJ"><u>selects “double” fractional binary representation for its prices</u></a>. This is an unfortunate choice, a worse one than using a precise representation: fractional decimal numbers input by the user are <em>never</em> represented precisely by their corresponding binary form. So all the numbers are incorrect but “close enough” that it works overall, and the only way to display a clean final result is by rounding to a suitable number of digits at the time of rendering a report. One could argue that the large number of digits provided by a 64-bit double representation is unlikely to cause significant errors given the quantity of operations we make… but binary rounding error could potentially accumulate, and the numbers are basically all incorrectly stored internally, rounded to their closest binary relative. Given that our task is accounting, why not just represent them correctly?</p>
<p>Hledger (since 2014) stores numbers internally as <a href="https://hackage.haskell.org/package/Decimal"><u>decimals</u></a> allowing "unlimited" integral digits and up to 255 decimal digits.</p>
<p>Secondly, when checking that the postings of a transaction balance to zero, with all three systems it is necessary to allow for some tolerance on those amounts. This need is clear when you consider that inputting numbers in a text file implies a limited decimal representation. For example, if you’re going to multiply a number of units and a cost, say both written down with 2 fractional digits, you might end up with a number that has 4 fractional digits, and then you need to compare that result with a cash amount that would typically be entered with only 2 fractional digits. You need to allow for some looseness somehow.</p>
<p>The systems differ in how they choose that tolerance:</p>
<ul>
<li>
<p>Ledger attempts to automatically derive the precision to use for its balance checks by using recently parsed context (in file order). The precision to be used is that of the last value parsed for the particular commodity under consideration. This can be problematic: it can lead to <a href="https://groups.google.com/d/msg/ledger-cli/m-TgILbfrwA/cTHg2juqEJgJ"><u>unnecessary side-effects between transactions which can be difficult to debug</u></a>.</p>
</li>
<li>
<p>HLedger, on the other hand, uses global precision settings. <a href="https://groups.google.com/d/msg/ledger-cli/m-TgILbfrwA/SoGZDNhlDOkJ"><u>The whole file is processed first, then the precisions are derived from the most precise numbers seen in the entire input file.</u></a></p>
<p>Hledger, on the other hand, uses the global display precisions of each commodity. The whole file is processed first, detecting an inferred or configured display precision for each commodity. Then a transaction is considered balanced if its sum appears zero when displayed with those precisions. (In future Hledger might balance using only local precisions inferred from the current journal entry, for better locality and robustness.)</p>
</li>
<li>
<p>At the moment, Beancount uses a constant value for the tolerance used in its balance checking algorithm (0.005 of any unit). This is weak and should, at the very least, be commodity-dependent, if not also dependent on the particular account in which the commodity is used. Ultimately, it depends on the numbers of digits used to represent the particular postings. We have a <a href="precision_tolerances.html"><u>proposal</u></a> en route to fix this.</p>
Expand Down
10 changes: 5 additions & 5 deletions api_reference/beancount.core.html
Original file line number Diff line number Diff line change
Expand Up @@ -3225,7 +3225,7 @@ <h4 id="beancount.core.amount.Amount.from_string" class="doc doc-heading">


<h4 id="beancount.core.amount.Amount.to_string" class="doc doc-heading">
<code class="highlight language-python">beancount.core.amount.Amount.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x749446ea74d0&gt;)</code>
<code class="highlight language-python">beancount.core.amount.Amount.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x77a204a6f200&gt;)</code>


<a href="#beancount.core.amount.Amount.to_string" class="headerlink" title="Permanent link"></a></h4>
Expand Down Expand Up @@ -7622,7 +7622,7 @@ <h3 id="beancount.core.data.new_directive" class="doc doc-heading">
<th class="field-name">Returns:</th>
<td class="field-body">
<ul class="first simple">
<li><p><code>&lt;function NamedTuple at 0x749447011120&gt;</code> – A type object for the new directive type.</p></li>
<li><p><code>&lt;function NamedTuple at 0x77a204bd51c0&gt;</code> – A type object for the new directive type.</p></li>
</ul>
</td>
</tr>
Expand Down Expand Up @@ -14009,7 +14009,7 @@ <h4 id="beancount.core.inventory.Inventory.segregate_units" class="doc doc-headi


<h4 id="beancount.core.inventory.Inventory.to_string" class="doc doc-heading">
<code class="highlight language-python">beancount.core.inventory.Inventory.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x749446ea74d0&gt;, parens=True)</code>
<code class="highlight language-python">beancount.core.inventory.Inventory.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x77a204a6f200&gt;, parens=True)</code>


<a href="#beancount.core.inventory.Inventory.to_string" class="headerlink" title="Permanent link"></a></h4>
Expand Down Expand Up @@ -15847,7 +15847,7 @@ <h4 id="beancount.core.position.Position.sortkey" class="doc doc-heading">


<h4 id="beancount.core.position.Position.to_string" class="doc doc-heading">
<code class="highlight language-python">beancount.core.position.Position.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x749446ea74d0&gt;, detail=True)</code>
<code class="highlight language-python">beancount.core.position.Position.to_string(self, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x77a204a6f200&gt;, detail=True)</code>


<a href="#beancount.core.position.Position.to_string" class="headerlink" title="Permanent link"></a></h4>
Expand Down Expand Up @@ -16254,7 +16254,7 @@ <h3 id="beancount.core.position.get_position" class="doc doc-heading">


<h3 id="beancount.core.position.to_string" class="doc doc-heading">
<code class="highlight language-python">beancount.core.position.to_string(pos, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x749446ea74d0&gt;, detail=True)</code>
<code class="highlight language-python">beancount.core.position.to_string(pos, dformat=&lt;beancount.core.display_context.DisplayFormatter object at 0x77a204a6f200&gt;, detail=True)</code>


<a href="#beancount.core.position.to_string" class="headerlink" title="Permanent link"></a></h3>
Expand Down
8 changes: 4 additions & 4 deletions api_reference/beancount.parser.html
Original file line number Diff line number Diff line change
Expand Up @@ -3785,7 +3785,7 @@ <h3 id="beancount.parser.cmptest.TestError" class="doc doc-heading">


<h3 id="beancount.parser.cmptest.assertEqualEntries" class="doc doc-heading">
<code class="highlight language-python">beancount.parser.cmptest.assertEqualEntries(expected_entries, actual_entries, failfunc=&lt;function fail at 0x74944608c540&gt;, allow_incomplete=False)</code>
<code class="highlight language-python">beancount.parser.cmptest.assertEqualEntries(expected_entries, actual_entries, failfunc=&lt;function fail at 0x77a203e78220&gt;, allow_incomplete=False)</code>


<a href="#beancount.parser.cmptest.assertEqualEntries" class="headerlink" title="Permanent link"></a></h3>
Expand Down Expand Up @@ -3886,7 +3886,7 @@ <h3 id="beancount.parser.cmptest.assertEqualEntries" class="doc doc-heading">


<h3 id="beancount.parser.cmptest.assertExcludesEntries" class="doc doc-heading">
<code class="highlight language-python">beancount.parser.cmptest.assertExcludesEntries(subset_entries, entries, failfunc=&lt;function fail at 0x74944608c540&gt;, allow_incomplete=False)</code>
<code class="highlight language-python">beancount.parser.cmptest.assertExcludesEntries(subset_entries, entries, failfunc=&lt;function fail at 0x77a203e78220&gt;, allow_incomplete=False)</code>


<a href="#beancount.parser.cmptest.assertExcludesEntries" class="headerlink" title="Permanent link"></a></h3>
Expand Down Expand Up @@ -3978,7 +3978,7 @@ <h3 id="beancount.parser.cmptest.assertExcludesEntries" class="doc doc-heading">


<h3 id="beancount.parser.cmptest.assertIncludesEntries" class="doc doc-heading">
<code class="highlight language-python">beancount.parser.cmptest.assertIncludesEntries(subset_entries, entries, failfunc=&lt;function fail at 0x74944608c540&gt;, allow_incomplete=False)</code>
<code class="highlight language-python">beancount.parser.cmptest.assertIncludesEntries(subset_entries, entries, failfunc=&lt;function fail at 0x77a203e78220&gt;, allow_incomplete=False)</code>


<a href="#beancount.parser.cmptest.assertIncludesEntries" class="headerlink" title="Permanent link"></a></h3>
Expand Down Expand Up @@ -9662,7 +9662,7 @@ <h4 id="beancount.parser.options.OptGroup.__repr__" class="doc doc-heading">


<h3 id="beancount.parser.options.Opt" class="doc doc-heading">
<code class="highlight language-python">beancount.parser.options.Opt(name, default_value, example_value=&lt;object object at 0x7494475894f0&gt;, converter=None, deprecated=False, alias=None)</code>
<code class="highlight language-python">beancount.parser.options.Opt(name, default_value, example_value=&lt;object object at 0x77a2051893e0&gt;, converter=None, deprecated=False, alias=None)</code>


<a href="#beancount.parser.options.Opt" class="headerlink" title="Permanent link"></a></h3>
Expand Down
2 changes: 1 addition & 1 deletion api_reference/beancount.tools.html
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ <h3 id="beancount.tools.treeify.create_tree" class="doc doc-heading">


<h3 id="beancount.tools.treeify.dump_tree" class="doc doc-heading">
<code class="highlight language-python">beancount.tools.treeify.dump_tree(node, file=&lt;_io.StringIO object at 0x749444f21780&gt;, prefix='')</code>
<code class="highlight language-python">beancount.tools.treeify.dump_tree(node, file=&lt;_io.StringIO object at 0x77a202d1da80&gt;, prefix='')</code>


<a href="#beancount.tools.treeify.dump_tree" class="headerlink" title="Permanent link"></a></h3>
Expand Down
2 changes: 1 addition & 1 deletion api_reference/beancount.utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -4422,7 +4422,7 @@ <h3 id="beancount.utils.misc_utils.import_curses" class="doc doc-heading">


<h3 id="beancount.utils.misc_utils.is_sorted" class="doc doc-heading">
<code class="highlight language-python">beancount.utils.misc_utils.is_sorted(iterable, key=&lt;function &lt;lambda&gt; at 0x749446c30cc0&gt;, cmp=&lt;function &lt;lambda&gt; at 0x749446c30d60&gt;)</code>
<code class="highlight language-python">beancount.utils.misc_utils.is_sorted(iterable, key=&lt;function &lt;lambda&gt; at 0x77a20480cae0&gt;, cmp=&lt;function &lt;lambda&gt; at 0x77a20480cb80&gt;)</code>


<a href="#beancount.utils.misc_utils.is_sorted" class="headerlink" title="Permanent link"></a></h3>
Expand Down
1 change: 1 addition & 0 deletions external_contributions.html
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ <h2 id="interfaces-web">Interfaces / Web<a id="interfaces-web"></a><a class="hea
<p><a href="https://github.com/SEIAROTg/autobean/tree/master/autobean/refactor"><u>autobean/refactor</u></a> (Archimedes Smith): Tooling to programmatically edit one's ledger, including formatting, sorting, refactoring, rearranging accounts, optimizing via plugins, migration from v2, inserting transactions in a ledger on import, and more.</p>
<p><a href="https://github.com/seltzered/beancolage"><u>seltzered/beancolage</u></a> (Vivek Gani): An Eclipse Theia (vendor-agnostic vscode) app that tries to bundle existing beancount-based packages such as vscode-beancount and Fava.</p>
<p><a href="http://aaronstacy.com/personal-finances-dashboard/"><u>aaronstacy.com/personal-finances-dashboard</u></a> : HTML + D3.js visualization dashboard for Beancount data.</p>
<p><a href="https://github.com/aleyoscar/beancount-pulsar"><u>https://github.com/aleyoscar/beancount-pulsar</u></a> : A Pulsar package for Beancount - Plain Text Accounting, with syntax highlighting, toggling comments, snippets for some directives and automatic indentation. Pulsar package: <a href="https://web.pulsar-edit.dev/packages/beancount-pulsar"><u>https://web.pulsar-edit.dev/packages/beancount-pulsar</u></a></p>
<h2 id="mobilephone-data-entry">Mobile/Phone Data Entry<a id="mobilephone-data-entry"></a><a class="headerlink" href="#mobilephone-data-entry" title="Permanent link"></a></h2>
<p><a href="https://play.google.com/store/apps/details?id=link.beancount.mobile"><u>Beancount Mobile</u></a> App (Kirill Goncharov): A mobile data entry app for Beancount. (Currently only Android is supported.) Repo: <a href="https://github.com/xuhcc/beancount-mobile"><u>https://github.com/xuhcc/beancount-mobile</u></a> (<a href="https://groups.google.com/d/msgid/beancount/014e0879-70e0-4cac-b884-82d8004e1b43%40googlegroups.com?utm_medium=email&amp;utm_source=footer"><u>Announcement</u></a>).</p>
<p><a href="http://costflow.io/"><u>http://costflow.io</u></a>: Plain Text Accounting in WeChat. "<em>Send a message to our bot in Telegram, Facebook Messenger, Whatsapp, LINE, WeChat, etc. Costflow will transform your message into Beancount / Ledger / hledger format transaction magically. Append the transaction to the file in your Dropbox / Google Drive. With the help of their apps, the file will be synced to your computer.</em>"</p>
Expand Down
Loading

0 comments on commit 43bcede

Please sign in to comment.