[GNC-dev] gnc_numeric division with how=GNC_HOW_DENOM_LCD
John Ralls
jralls at ceridwen.us
Sat May 19 11:49:10 EDT 2018
> On May 19, 2018, at 2:28 AM, Geert Janssens <geert.gnucash at kobaltwit.be> wrote:
>
> Christopher Lam is busy writing unit tests for our business reports which is
> great.
>
> However he has run into a peculiar issue in that he can't create a test
> invoice entries that properly handle tax or percentages.
>
> I have been tracing in the debugger and I ran into a peculiar bug for which I
> need some feedback.
>
> The core of the issue is in this line:
> https://github.com/Gnucash/gnucash/blob/maint/libgnucash/engine/
> gncEntry.c#L1139
>
> This division is to convert a number as entered by the user into a percentage
> value.
> The user enters "10", which the code should interpret as 10%, or 0.01
>
> This works fine with numbers entered by real users in the user interface,
> however it fails when generating these same numbers via scheme code.
>
> And this is because both get a different denominator: all user entered numbers
> (in this context) will be stored with a denom of 100000. However when you make
> a scheme rational 1000000/100000 (so equivalent to 10), it gets reduced to
> 10/1 by the time it's used in the line above. Clearly guile automatically
> reduces rationals.
>
> The net effect is that for user entered numbers the line above will divide
> 1000000/100000 by 100/1 while for scheme generated numbers the division
> becomes 10/1 by 100/1.
>
> Combining this with how=GNC_HOW_DENOM_LCD makes that the denominator will be
> fixed to 1 causing 0.1/1 to be rounded to 0.
>
> That's the symptom. But I do have some difficulty determining the actual
> cause: is gnc_numeric_div doing the wrong thing with GNC_HOW_DENOM_LCD ? That
> would make it a bug in gnc_numeric_div. In a division I would expect the
> nominator of the divisor to be taken into account to calculate the LCD but
> perhaps my (accounting related) math is wrong.
> Or perhaps GNC_HOW_DENOM_LCD just doesn't make sense for a division and
> another rounding method should be used here? That would make it a bug in the
> gncEntryComputeValueInt function.
> Or both are right and I should just ensure to have a proper common denominator
> somehow. I could maybe set percent in the calculation above to 10000000/100000
> instead of to 100/1.
> Or I could avoid gnc_numeric_div altogether by multiplying with 1/100 instead.
>
> However I wanted some feedback before applying one of the workarounds to be
> sure I'm not masking a a more important bug that way.
>
For reference, the line in question is
tpercent = gnc_numeric_div (tpercent, percent, GNC_DENOM_AUTO,
GNC_HOW_DENOM_LCD);
Note in particular the warning at https://github.com/Gnucash/gnucash/blob/maint/libgnucash/engine/gnc-numeric.h#L80 <https://github.com/Gnucash/gnucash/blob/maint/libgnucash/engine/gnc-numeric.h#L80>
that the fractional part of a number may be discarded if you don’t specify a rounding policy. This call has a denominator setting but no rounding policy.
I think GNC_HOW_DENOM_LCD doesn’t make sense for most divisions, it’s very likely that one wants more precision than the smaller of the operands' denominators. I think for this case you want GNC_HOW_DENOM_EXACT | GNC_HOW_ROUND_NEVER or GNC_HOW_DENOM_REDUCE | GNC_HOW_ROUND_NEVER: That preserves all of the precision that a user enters, though it does present the (small) possibility of an overflow error. GNC_HOW_DENOM_REDUCE | GNC_HOW_ROUND_RND will trade the small possibility of an overflow for the small possibility of a rounding error in the actual tax calculation.
Multiplying 10/1 by 1/100 won’t change anything: The LCD is still 1.
Regards,
John Ralls
More information about the gnucash-devel
mailing list