Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert to Float without Rounding Decimal Places

I have a list and it contains a certain number '5.74536541' in it which I convert to a float.

I am printing it out in Python 3 using ("%0.2f" % (variable)) but it always prints out 5.75 instead of 5.74.

I know you're thinking who cares, but it is for a currency converter program and I don't want the currencies to round up/down but to be exact.

How can I keep it from rounding but also keep the 2 decimal places?

like image 961
Goose Avatar asked Dec 11 '22 20:12

Goose


2 Answers

You shouldn't use floating point numbers for currency, due to rounding errors like you mentioned.

Your best bet is to use a fixed-precision decimal where you also have full control over how rounding and truncation works. 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 should represent all currency-based values internally as Decimals with a high precision (the standard level of precision should be fine in your case - just leave the prec alone!). If you want to print a nicely formatted dollars and cents value to the user, using the locale module is a straightforward way to do this.

Be careful when printing as you will have to quantize the Decimal down to the correct number of places for display or the rounding will not be based on your Decimal context! You should only perform the quantize step for final display or for a single, final value - all intermediate steps should use high-precision Decimals 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'
like image 111
John Lyon Avatar answered Dec 28 '22 07:12

John Lyon


If you're dealing with currency and accuracy matters, don't use float, use decimal.

like image 25
Mark Ransom Avatar answered Dec 28 '22 06:12

Mark Ransom