Accurant percentage calculation of decimal values in Python


My goal is to accurantly add or remove 0.05% from values with 18 decimals in Python without converting them to floats. I made the two following solutions and they seem correct for me, but I am very unfamiliar with numbers in Python, therefore I would like to know if there’s a better (in terms of accurancy) solution.

price_in_wei = 1000000000000000000 # = 1

# -0.05%
price_with_fee = (price_in_wei/1000)*995

# +0.05%
price_with_fee = (price_in_wei/1000)*1005

# -0.05%
price_with_fee = (price_in_wei*995)/1000

# +0.05%
price_with_fee = (price_in_wei*1005)/1000


Let me suggest that you use decimal arithmetic using class decimal.Decimal. Even if you need the final result to be an integer value, using decimal arithmetic for intermediate calculations will provide greater accuracy. For the example you provided, what you are doing in the second set of calculations work well enough but only because of the specific values used. What if price_in_wei were instead 1000000000000000001? Your calculation would yield 9.95e+17 or, if converted to an int, 99500000000000000:

>>> price_in_wei
>>> price_with_fee = price_in_wei*995/1000
>>> price_with_fee
>>> int(price_with_fee)

But decimal arithmetic provides greater precision:

>>> from decimal import Decimal
>>> price_with_fee = Decimal(price_in_wei) * 995 / 1000
>>> price_with_fee
>>> price_with_fee = int(price_with_fee.quantize(Decimal(1))) # round to an integer and convert to int
>>> price_with_fee

But let’s say your currency were US Dollars, which supports two places of precision following the decimal point (cents). If you want that precision, you should work exclusively with decimal arithmetic. For example:

>>> from decimal import Decimal, ROUND_HALF_UP
>>> price_in_wei = Decimal('1000000000000000003')
>>> price_with_fee = (price_in_wei * 995 / 1000).quantize(Decimal('1.00'), decimal.ROUND_HALF_UP) # round to two places
>>> price_with_fee

Answered By – Booboo

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published