Rounding in the price db.

John Ralls jralls at ceridwen.us
Tue Aug 11 04:20:43 EDT 2015


> On Aug 10, 2015, at 10:44 PM, Mike Alexander <mta at umich.edu> wrote:
> 
> --On August 10, 2015 at 4:27:40 PM +0100 John Ralls <jralls at ceridwen.us> wrote:
> 
>>> I seem to remember that banks here use 6 significant digits in
>>> exchange  rates, which is not quite the same as 6 places after the
>>> decimal point.  Your USD-Sao Tomean Dobra illustrates this: due to
>>> the extreme value  difference between the two you need 10 digits
>>> after the decimal point,  but only 6 of them are significant (ie not
>>> a leading zero).
>>> 
>>> Is this something our gnc_numeric code supports and can be used by
>>> the  price db ?
>> 
>> We have “significant digits” rounding code, but IIRC it’s
>> really six decimal places. If we were to have real significant digits
>> we’d need to be careful to keep it away from the debits-and-credits
>> code or it could make a real mess.
> 
> Six significant digits would probably do, although I would argue for a few more to properly convert large quantities of a commodity.  However 10 decimal places is easier to implement and is probably just as good. That seems to be what the XE conversion tables at <http://www.xe.com/currencytables/> use. Even that falls down converting gold to Sao Tomean Dobra, but it works ok for any real currency.  It gives 6 digits of accuracy converting between Kuwaiti Dinar and Sao Tomean Dobra which is the biggest ratio I can find.

Hmm. That’s doable in master with careful rounding control. I’m pretty sure it would produce overflows in maint because the old int128 math is really int128-int64 and it barfs if any intermediate result won’t fit in int64_t. On the other hand, the current implementation with no rounding is likely to produce overflows if one tries to do a large transaction in Dinars->Dobe (or Bitcoin to a lot of minor currencies, for that matter). ISTM arbitrarily setting a 10^-10 rounding isn’t quite right, though. If we’re going to do something like that, and see the next para, it would be more correct to round to the number of digits which make a 1-scu change in the smaller currency or perhaps one more digit than that. 10 digits might not be enough for converting STD to BTC with its 10^-6 scu.

The whole issue of restricting denominators to powers of 10, implied by “significant digits” and “decimal places" is also worthy of discussion. Both terms are meaningless with rational numbers unless one imposes that constraint. Once one does, though, significant digits is no more difficult to implement than decimal places: One just rounds the numerator to x digits after doing the denominator conversion, adjusting the denominator to account for any reduction of the digits in the numerator.

None of which does anything to help deal with the small moves in prices due to rounding in the amount and value to their respective SCUs getting recorded in the pricedb. Mike’s recommendation to capture the user input works in the case where the user inputs (or retrieves from F::Q) a price, but not if she uses the other-account-amount entry. IIRC I implemented the price db storage as after-rounding-to-scu so that there’d be only one place in the code where it was written out. That can be changed easily enough and might reduce some of the complaints about the presented price jumping around when entering a bunch of foreign currency transactions. *That* change could go in maint. I clearly hadn’t sufficiently thought through rounding when I started this thread. It seems sufficiently complicated that any implementation should go into master instead.

We seem to agree that there need be only one price per day in the price db, but no one’s said anything about what price that should be. I’m inclined towards any new price replaces the existing one unless they’re the same. What about source? Should a F::Q price take precedence over a transfer dialog price or vice-versa?

Regards,
John Ralls





More information about the gnucash-devel mailing list