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.
