← Back to team overview

openerp-expert-accounting team mailing list archive

wrong currency rounding

 

I'm forwarding this mail to list as it is relevant and seems it was
not delivered

---------- Forwarded message ----------
From: Olivier Dony <odo@xxxxxxxxxxx>
Date: 2011/11/7
Subject: Re: [Bug 865387] Re: wrong currency rounding
To: Lorenzo Battistini <lorenzo.battistini@xxxxxxxxxxx>
Cc: openerp-expert-accounting@xxxxxxxxxxxxxxxxxxx


On 11/06/2011 06:42 PM, Lorenzo Battistini wrote:
> I have one more doubt about floats: how could I manage this
>
>>>> round(2.675, 2)
> 2.67

The key idea here is that you should not be rounding the decimal value
to a smaller number of decimal digits directly, because the
representational bias will have too big an influence.
The error, as you probably saw, comes from the fact that 2.675 cannot be
represented exactly as a floating point, and the closest IEEE 754
representation is "2.674999...", which rounds logically to 2.67.

Instead, you should round to an integer to minimize the representation
bias, based on the precision you're looking for.
For example, if you want a precision of 2 decimal digits, you'll
multiply the float value by 100, round to the closest integer, then
divide by 100 again. That new result will be an IEEE-754 representation
that is close enough to the x-digit decimal precision to be represented
correctly.
It could be 2.679999999... or 2.680000001.., but in all cases an amount
that will always be rounded to 2.68 for printing/storing purposes.

>>> print round(2.675 * 100) / 100
2.68
>>> print "%.25f" % (round(2.675 / 0.01) * 0.01,)
2.6800000000000001598721155

This is exactly what res.currency.round() does, too.

We should probably provide generic round(value,precision) and
is_zero(value,precision) methods in our builtin tools, as those in
res.currency are tied to a currency record (or at least an object with a
'rounding' attribute)

Hope this helps...


Follow ups

References