I've found many posts regarding rounding in python, but from my understanding none so far solves my problem.
Two solutions I'm looking for:
Round closest: float/string numbers which need to be rounded differently depending on their size.
Round down: float/string numbers which need to be rounded down differently depending on their size.
Round up: float/string numbers which need to be rounded up differently depending on their size.
Example:
The resulting variable should be a string.
The neat thing I'm, looking for is a function in which i can pass number of decimals and fraction
You can use the Decimal module for highly customizable rounding:
import decimal
def rnd(f,n,r=decimal.ROUND_HALF_DOWN):
pat='1.'+'0'*n
return str(decimal.Decimal(str(f)).quantize(decimal.Decimal(pat),r))
Now to test:
for n in (500.99,100.39,5.019):
for i in (0,1,2):
print('n={:10}, i={:2}, Down: {:>10}, Closest: {:>10}'.format(n,i, rnd(n,i,decimal.ROUND_FLOOR),rnd(n,i)))
Prints:
n= 500.99, i= 0, Down: 500, Closest: 501
n= 500.99, i= 1, Down: 500.9, Closest: 501.0
n= 500.99, i= 2, Down: 500.99, Closest: 500.99
n= 100.39, i= 0, Down: 100, Closest: 100
n= 100.39, i= 1, Down: 100.3, Closest: 100.4
n= 100.39, i= 2, Down: 100.39, Closest: 100.39
n= 5.019, i= 0, Down: 5, Closest: 5
n= 5.019, i= 1, Down: 5.0, Closest: 5.0
n= 5.019, i= 2, Down: 5.01, Closest: 5.02
(Note: This is different output in the case of 1 decimal and the input of 100.39
. Please clarify the desired output of 100.2
in that case? Shouldn't the output be 100.3
?)
With the clarification, I think you just need to use fmod
:
import math
def rnd(n,f,prec,direction='down'):
if direction=='down':
if prec==0:
return str(int(n))
return str(round(n-math.fmod(n,f),prec))
else:
if prec==0:
return str(int(round(n)))
n+=f
return str(round(n-math.fmod(n,f),prec))
Works with all examples given:
>>> rnd(500.99,0.1,0)
'500'
>>> rnd(500.99,0.1,0,'')
'501'
>>> rnd(100.39,0.2,1,'')
'100.4'
>>> rnd(100.39,0.2,1)
'100.2'
>>> rnd(100.59,0.2,1,'')
'100.6'
>>> rnd(100.59,0.2,1)
'100.4'
>>> rnd(5.019,0.01,2)
'5.01'
>>> rnd(5.019,0.01,2,'')
'5.02'
(Call the function with the direction=
keyword argument with any string value other than 'down'
to get up. Change to your liking...)
This returns the method closest to the input number:
def rnd(n,f,prec):
n1=int(n) if prec==0 else round(n-math.fmod(n,f),prec)
n2=float(int(round(n))) if prec==0 else round((n+f)-math.fmod((n+f),f),prec)
return str(min((n1,n2), key=lambda e: math.fabs(e-n)))