You should not use floating point numbers for currencies due to rounding errors, as you mentioned.
It is best to use fixed-precision decimal , where you also have full control over how rounding and trimming work. From the docs:
>>> from decimal import * >>> getcontext() Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1, flags=[], traps=[Overflow, DivisionByZero, InvalidOperation]) >>> getcontext().prec = 6 >>> Decimal('3.0') Decimal('3.0') >>> Decimal('3.1415926535') Decimal('3.1415926535') >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal('5.85987') >>> getcontext().rounding = ROUND_UP >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal('5.85988')
You must represent all currency-based values ββas Decimals with high precision (the standard level of accuracy must be accurate in your case - just leave prec alone!). If you want to print a beautifully formatted dollar and cents for the user, using the locale module is an easy way to do this.
Be careful when printing, because you will need to quantize decimal to the number of places to display, or rounding will not be based on your decimal context! You should only perform the quantize step for the final display or for one final value - all intermediate steps should use a high-precision decimal to make any operations as accurate as possible.
>>> from decimal import * >>> import locale >>> locale.setlocale(locale.LC_ALL, '') 'en_AU.UTF-8' >>> getcontext().rounding = ROUND_DOWN >>> TWOPLACES = Decimal(10) ** -2 >>> var = Decimal('5.74536541') Decimal('5.74536541') >>> var.quantize(TWOPLACES) Decimal('5.74') >>> locale.currency(var.quantize(TWOPLACES)) '$5.74'
source share