Very interesting discussion. Comments inserted below.

On Mon, Jun 23, 2014 at 6:06 PM, Martin Michlmayr <[email protected]> wrote:

> TL;DR: There are various rounding-related issues in ledger.  This
> email (a) shows the problems we've encountered, (b) proposes some
> ideas for new directives that might be useful, and c) ends with some
> open questions for discussion on this list.
>
>
> [...]


> Just imagine a conversation with your accounting.  "So you spent
> $27.54 and then you spent $27.54, but your total expenses are $55.09?
> Why is that?" "Oh, you know, the expenses weren't really $27.54...
> they were actually $27.543834".  No, they weren't.  In practice, each
> expense was $27.54.
>

So far all of the examples you brought up point to an obvious
implementation choice:

  "Rounding should occur at the point of calculating the "balance amount",
that is, the amount that is used to balance against the rest of the
postings of the transaction."



One final example: you buy 123 shares for 1.23456 each and later sell
> them for 2.345 each.  So first of all, how much money do you get?
> 123*2.345 = 288.435.  But do you really get that amount?  No, you get
> 288.44 if you're lucky (or 288.43 if you're not).
>
> And how much capital gain was there?  Again, the maths is simple:
> 123*(2.345-1.23456) = 136.58412
>
> But are you really going to tell your tax authority that you made a
> gain of 136.58412?  No, you're going to tell them 136.58 (or 136.59).
>

Actually... in my experience, any reasonable tax authority would accept you
making calculations using that more precise reporting. The more intimately
I deal with those guys, the more I realize how relative things can be.
Nevertheless...



Here's this example in ledger:
>
> D 1000.00 EUR
>
> 2014-06-01 * Opening balance
>     Assets:Investments            123 XXX {1.23456 EUR} @ 1.23456 EUR
>     Equity:Opening balances          -151.85 EUR
>
> 2014-06-22 * Sell some shares
>     Assets:Investments            -123 XXX {1.23456 EUR} @ 2.345 EUR
>     Assets:Cash                        288.44 EUR
>     Income:Capital gains              -136.59 EUR
>
> This balances and works fine.  But if you change "D 1000.00 EUR" to
> "D 1000.000 EUR", suddenly it won't balance:
>
> Unbalanced remainder is:
>           -0.001 EUR
> Amount to balance against:
>          288.440 EUR
>
> This shouldn't happen.  The display precision shouldn't affect the
> calculation: as you can see from these examples, the extra ledger
> keeps internally is causing lots of problems in real life.
>

I've had this problem too, in a currency trading account, and so far my
solution has been to admit a 1.5c delta difference in balance checks. This
has worked so far, but I don't like its grittiness. At the moment this is
not configurable but I will make it be (via an option).



Now it's great that ledger can keep precision if there's a need, but
> in most real-life scenarios, we want to round to 2 digits of
> precision.
>

I think the question should be phrased in terms of what precision you want
to represent numbers _internally_. Isn't a worthy goal to attempt to
replicate the same precision as the real-world accounts they represent?



Possible solution
> -----------------
>
> We could have a "commodity" directive called "precision" (or something
> similar):
>
> commodity EUR
>     precision 2
>
> This would tell ledger to round to 2 digits of precision.  This
> rounding is done internally, i.e. ledger wouldn't keep more detail
> than that precision.
>
> But is this enough?  I think we also need the ability to specify *how*
> rounding is done?  In most cases, it's probably just rounded properly,
> i.e.  0.005+ is rounded up, everything below is rounded down.
>

I think it gets a bit more complicated than this.
The IEEE standard for decimal numbers has defined various specific methods
for rounding.
See the Python implementation doc for some references to it, or mpdecimal:
https://docs.python.org/2/library/decimal.html
http://www.bytereef.org/mpdecimal/doc/cdecimal/index.html

Lots more info here:
http://speleotrove.com/decimal/

(FWIW in Beancount I use the "cdecimal" Python wrapper to mpdecimal, for
performance reasons.)



But I can imagine that some companies just truncate: so even if you
> should get 1.126, they would give you 1.12 instead of 1.23.  (I don't
> actually know if this is true, but it might be.)
>

I doubt it; this is a common problem. That bank would have to have _really_
bad developers for this to be the case. In your researching previous work,
you might want to dig into banking regulation law, there might be something
in there that mentions this. I wonder if you call your bank to ask them how
they do it if they'd share... you're a customer after all. Fun experiment.



And maybe there should be one option to make rounding "flexible" or
> "permissive": in the example above, ledger would accept both 1.12 and
> 1.13 for the balancing check, so both of these examples would work:
>
> 2014-06-23 * Test 1
>     A         1 AAA @ $1.126
>     B         $1.13
>
> 2014-06-23 * Test 2
>     A         1 AAA @ $1.126
>     B         $1.12
>
> I guess these are actually two separate questions: how should ledger do
> rounding if nothing is specified for B:
> 2014-06-23 * Test 2
>     A         1 AAA @ $1.126
>     B
> Is B $1.13 or $1.12?
>

If you state that rounding should occur when computing the balance amount,
the answer is unambiguous: $-1.13.


And the second: what should ledger accept for the balancing check if
> the user specifies a value as B (i.e. so either of the example above
> is accepted).
>

Only -1.13.
IMHO it is reasonable for an input of -1.126 to trigger an error, that is,
if you have a clearly specified rounding rule.



Anyway, we could have something like (and possibly another directive
> to say how "permissive" balancing should be):
>
> commodity EUR
>     precision 2
>     rounding truncate
>
> While precision is probably the same for one currency regardless of
> the account, you should be able to specify the type of rounding for
> each account (one bank may round properly while another may always
> truncate):
>
> account Foo
>    rounding truncate
>
> account Bar
>    rounding round
>

I have a use case for this: a real-world currency trading account which
rounds its precision at 4 digits instead of the customary two. Amounts are
tracked in US dollars. Transfers in and out are using two digits, but
internally, four are preserved.  (This is an argument against specifying it
by commodity.)




In addition to these commodity/account directives, it might also be useful
> to specify rounding on the command line to force it once.  I'm not sure if
> there's a use case for this.
>
> Open questions
> --------------
>
> * Do we actually need to specify the precision?  After all, ledger
> keeps track of the precision you use in your input data (and by
> default uses that for the display precision).  Maybe we should just
> use that precision as the precision for rounding if rounding is
> enabled.  In other words, we wouldn't need the "precision" directive
> -- "rounding" would be enough.  I cannot think of any use cases where
> this wouldn't work, but maybe I'm missing something. (See below for
> rounding to 1000s)


> * If we do implement a "precision" directive and someone says
> "precision 2", what would happen if someone then wrote a value like
> 10.123.  Should this be rejected or should it override precision?
>

Where is rounding defined to occur?
You have to state a rule IMO.


* What about currencies like CAN and AUD which have phased out the
> cent coin?  The smallest coin is 5c.  I *assume*, bank and investment
> accounts still show single cents, but I'm not sure (Martin Blais, can
> you comment?).
>

Oh have they finally done that? I haven't noticed (I don't live there
anymore).
I think this would only apply to cash transactions anyhow.


* Does rounding only happen after the decimal point or are there
> currencies where 600 would be rounded to 1000?  (I'm thinking of
> currencies where one million or billion is worth $1 or so).  The
> proposal assumes that rounding only happens after the decimal point
> but maybe this assumption is wrong.
>

There's a lot of crazy stuff out there... I forget which it is, but I once
heard of an exotic currency that rounds at multiples of 5 in its integer
amount that gave some friends working in a financial institution an
implementation headache. (Personally I feel that you have to support
everything, others may disagree.)





* Does anyone know how banks/currency exchanges/investment companies
> actually do rounding in real life?  Do they round correctly or do some
> truncate?
>
> * How does Bitcoin work?  I know Bitcoin is divisible.  So would they
> want no rounding?
>   commodity BTC
>       rounding off  (or precision 0)
> Are there use cases where Bitcoin would be rounded?
>
> * How do other accounting packages handle rounding?
>
> * In the proposal above, I've assumed that users can specify rounding
> (e.g. "truncate") as a directive.  Another way to implement it would
> be to allow users to specify a function that does the rounding: this
> would be more powerful, but otoh, it makes things more difficult to
> use (and probably to implement).  And with a function, how do we know
> what should balance?
>
> --
> Martin Michlmayr
> http://www.cyrius.com/
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "Ledger" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"Ledger" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to