Round to nearest 0.05 using Python - python

How can I do the following rounding in python:
Round to the nearest 0.05 decimal
7,97 -> 7,95
6,72 -> 6,70
31,06 -> 31,05
36,04 -> 36,05
5,25 -> 5,25
Hope it makes sense.

def round_to(n, precision):
correction = 0.5 if n >= 0 else -0.5
return int( n/precision+correction ) * precision
def round_to_05(n):
return round_to(n, 0.05)

def round05(number):
return (round(number * 20) / 20)
Or more generically:
def round_to_value(number,roundto):
return (round(number / roundto) * roundto)
The only problem is because you're using floats you won't get exactly the answers you want:
>>> round_to_value(36.04,0.05)
36.050000000000004

There we go.
round(VALUE*2.0, 1) / 2.0
regards

Here's a one liner
def roundto(number, multiple):
return number+multiple/2 - ((number+multiple/2) % multiple)

Using lambda function:
>>> nearest_half = lambda x: round(x * 2) / 2
>>> nearest_half(5.2)
5.0
>>> nearest_half(5.25)
5.5
>>> nearest_half(5.26)
5.5
>>> nearest_half(5.5)
5.5
>>> nearest_half(5.75)
6.0

To round it to exactly how you want to:
>>> def foo(x, base=0.05):
... return round(base*round(x/base), 2)
>>> foo(5.75)
5.75
>>> foo(5.775)
5.8
>>> foo(5.77)
5.75
>>> foo(7.97)
7.95
>>> foo(6.72)
6.7
>>> foo(31.06)
31.05
>>> foo(36.04)
36.05
>>> foo(5.25)
5.25

I faced the same problem and as I didn't find the ultimate solution to this, here's mine.
Firs of all the main part(which was answered before):
def round_to_precision(x, precision):
# This correction required due to float errors and aims to avoid cases like:
# 100.00501 / 0.00001 = 10000500.999999998
# It has a downside as well - it may lead to vanishing the difference for case like
# price = 100.5 - (correction - correction/10), precision = 1 => 101 not 100
# 5 decimals below desired precision looks safe enough to ignore
correction = 1e-5 if x > 0 else -1e-5
result = round(x / precision + correction) * precision
return round(result, find_first_meaningful_decimal(precision))
The only tricky part here was that find_first_meaningful_decimal, which I've implemented like this:
def find_first_meaningful_decimal(x):
candidate = 0
MAX_DECIMAL = 10
EPSILON = 1 / 10 ** MAX_DECIMAL
while round(x, candidate) < EPSILON:
candidate +=1
if candidate > MAX_DECIMAL:
raise Exception('Number is too small: {}'.format(x))
if int(x * 10 ** (candidate + 1)) == 5:
candidate += 1
return candidate
print(round_to_precision(129.950002, 0.0005))
print(round_to_precision(-129.95005, 0.0001))
129.9505
-129.9501

import numpy as np
for Roundup
df['a']=(df["a"]*2).apply(np.ceil)/2
for Round
df['a']=(df["a"]*2).apply(np.floor)/2
This is working with columns for roundup 0.5 using numpy...

An extension of the accepted answer.
def round_to(n, precision):
correction = precision if n >= 0 else -precision
return round(int(n/precision+correction)*precision, len(str(precision).split('.')[1]))
test_cases = [101.001, 101.002, 101.003, 101.004, 101.005, 101.006, 101.007, 101.008, 101.009]
[round_to(-x, 0.003) for x in test_cases]
[-101.001, -101.001, -101.001, -101.004, -101.004, -101.004, -101.007, -101.007, -101.007]

Related

Rounding a float number in python

I have a float numer
a = 1.263597
I hope get
b = 1.2635
But when I try
round (a,4)
then result is
1.2636
What should I do?
Try math.floor with this small modification -
import math
def floor_rounded(n,d):
return math.floor(n*10**d)/10**d
n = 1.263597
d = 4
output = floor_rounded(n,d)
print(output)
1.2635
For your example, you can just do math.floor(1.263597 * 10000)/10000
EDIT: Based on the valid comment by #Mark, here is another way of solving this, but this time forcing the custom rounding using string operations.
#EDIT: Alternate approach, based on the comment by Mark Dickinson
def string_rounded(n,d):
i,j = str(n).split('.')
return float(i+'.'+j[:d])
n = 8.04
d = 2
output = string_rounded(n,d)
output
8.04
Plain Python without importing any libraries (even not standard libraries):
def round_down(number, ndigits=None):
if ndigits is None or ndigits == 0:
# Return an integer if ndigits is 0
return int(number)
else:
return int(number * 10**ndigits) / 10**ndigits
a = 1.263597
b = round_down(a, 4)
print(b)
1.2635
Note that this function rounds towards zero, i.e. it rounds down positive floats and rounds up negative floats.
def round_down(number, ndigits=0):
return round(number-0.5/pow(10, ndigits), ndigits)
Run:
round_down(1.263597, 4)
>> 1.2635

How to display a very accurate number?

I want to output two numbers that differ very slightly from each other.
1.0000000000
1.0000000001
I don't want a long line. Rounding or scientific notation doesn't help me.
>>> round(1.0000000000, 6)
1.0
>>> round(1.0000000001, 6)
1.0
>>> f"{1.0000000001:e}"
'1.000000e+00'
>>> f"{1.0000000000:e}"
'1.000000e+00'
I like the solution in matplotlib. There, the number is presented as the sum of the major part and fractional. So the numbers presented above will look like this:
1 + 0 * 1e-10,
1 + 1 * 1e-10
I can implement this myself, but suddenly you know any libraries or standard tools for this.
Do you know the existing tools for this?
Maybe library decimal is useful. For example:
>>> from decimal import Decimal
>>> a = Decimal(1.0000000000)
>>> b = Decimal(1.0000000001)
>>>
>>> a
Decimal('1')
>>> b
Decimal('1.0000000001000000082740370999090373516082763671875')
>>>
>>> a == b
False
I never got an answer.
So far I tried to implement the functionality of matplotib.
True, the code is crude, but I'll save it here, suddenly it will be useful to someone.
Pass the list of objects to Decimal!!!
def prepare_display(numbers, accuracy):
from decimal import Decimal
ACCURACY = 3
numbers_sorted = sorted(numbers)
diffs = []
for i in range(1, len(numbers)):
diffs.append(numbers_sorted[i] - numbers_sorted[i - 1])
if min(diffs) > 1 * 10 ** (-ACCURACY):
return '', numbers
total_part = min(numbers)
differents = []
exps = []
for number in numbers:
diff = number - total_part
differents.append(diff)
exps.append(fexp(diff))
min_exp = min(exps)
different_parts = []
for diff in differents:
different_parts.append(round(diff / Decimal(10 ** min_exp)))
total_part = Decimal(total_part)
return str(round(total_part, - min_exp - 1)) + ' + x * 1e' \
str(min_exp),
different_parts
def fexp(number):
"""Returns the exponent of a decimal number"""
from decimal import Decimal
(sign, digits, exponent) = Decimal(number).as_tuple()
return len(digits) + exponent - 1
Then for the following cases there will be a corresponding result.
For numbers less than one
>>>> numbers = [Decimal('0.999990'), Decimal('0.999992')]
>>>> total_part, different_parts = prepare_display(numbers)
>>>> print(total_part)
>>>> print(different_parts)
0.99999 + x * 1e-6
[0, 2]
If no conversion is needed
>>>> numbers = [1, 2]
>>>> total_part, different_parts = prepare_display(numbers, 3)
>>>> print(total_part)
>>>> print(different_parts)
[1, 2]
The code is very crude

round down to 0.05 in python( not round nearest) [duplicate]

How can I do the following rounding in python:
Round to the nearest 0.05 decimal
7,97 -> 7,95
6,72 -> 6,70
31,06 -> 31,05
36,04 -> 36,05
5,25 -> 5,25
Hope it makes sense.
def round_to(n, precision):
correction = 0.5 if n >= 0 else -0.5
return int( n/precision+correction ) * precision
def round_to_05(n):
return round_to(n, 0.05)
def round05(number):
return (round(number * 20) / 20)
Or more generically:
def round_to_value(number,roundto):
return (round(number / roundto) * roundto)
The only problem is because you're using floats you won't get exactly the answers you want:
>>> round_to_value(36.04,0.05)
36.050000000000004
There we go.
round(VALUE*2.0, 1) / 2.0
regards
Here's a one liner
def roundto(number, multiple):
return number+multiple/2 - ((number+multiple/2) % multiple)
Using lambda function:
>>> nearest_half = lambda x: round(x * 2) / 2
>>> nearest_half(5.2)
5.0
>>> nearest_half(5.25)
5.5
>>> nearest_half(5.26)
5.5
>>> nearest_half(5.5)
5.5
>>> nearest_half(5.75)
6.0
To round it to exactly how you want to:
>>> def foo(x, base=0.05):
... return round(base*round(x/base), 2)
>>> foo(5.75)
5.75
>>> foo(5.775)
5.8
>>> foo(5.77)
5.75
>>> foo(7.97)
7.95
>>> foo(6.72)
6.7
>>> foo(31.06)
31.05
>>> foo(36.04)
36.05
>>> foo(5.25)
5.25
I faced the same problem and as I didn't find the ultimate solution to this, here's mine.
Firs of all the main part(which was answered before):
def round_to_precision(x, precision):
# This correction required due to float errors and aims to avoid cases like:
# 100.00501 / 0.00001 = 10000500.999999998
# It has a downside as well - it may lead to vanishing the difference for case like
# price = 100.5 - (correction - correction/10), precision = 1 => 101 not 100
# 5 decimals below desired precision looks safe enough to ignore
correction = 1e-5 if x > 0 else -1e-5
result = round(x / precision + correction) * precision
return round(result, find_first_meaningful_decimal(precision))
The only tricky part here was that find_first_meaningful_decimal, which I've implemented like this:
def find_first_meaningful_decimal(x):
candidate = 0
MAX_DECIMAL = 10
EPSILON = 1 / 10 ** MAX_DECIMAL
while round(x, candidate) < EPSILON:
candidate +=1
if candidate > MAX_DECIMAL:
raise Exception('Number is too small: {}'.format(x))
if int(x * 10 ** (candidate + 1)) == 5:
candidate += 1
return candidate
print(round_to_precision(129.950002, 0.0005))
print(round_to_precision(-129.95005, 0.0001))
129.9505
-129.9501
import numpy as np
for Roundup
df['a']=(df["a"]*2).apply(np.ceil)/2
for Round
df['a']=(df["a"]*2).apply(np.floor)/2
This is working with columns for roundup 0.5 using numpy...
An extension of the accepted answer.
def round_to(n, precision):
correction = precision if n >= 0 else -precision
return round(int(n/precision+correction)*precision, len(str(precision).split('.')[1]))
test_cases = [101.001, 101.002, 101.003, 101.004, 101.005, 101.006, 101.007, 101.008, 101.009]
[round_to(-x, 0.003) for x in test_cases]
[-101.001, -101.001, -101.001, -101.004, -101.004, -101.004, -101.007, -101.007, -101.007]

Fix float precision with decimal numbers

a = 1
for x in range(5):
a += 0.1
print(a)
This is the result:
1.1
1.2000000000000002
1.3000000000000003
1.4000000000000004
1.5000000000000004
How can I fix this? Is the round() function the only way? Can I set the precision of a variable before setting its value?
can i set the precision of a variable before setting the value?
Use the decimal module which, unlike float(), offers arbitrary precision and can represent decimal numbers exactly:
>>> from decimal import Decimal, getcontext
>>>
>>> getcontext().prec = 5
>>>
>>> a = Decimal(1)
>>>
>>> for x in range(5):
... a += Decimal(0.1)
... print(a)
...
1.1000
1.2000
1.3000
1.4000
1.5000
You could format your output like this;
a=1
for x in range(5):
a += 0.1
print("{:.9f}".format(a) )
Assuming that your problem is only displaying the number, #Jaco 's answer does the job. However if you're concern about using that variable and potentially make comparisons or assigning to dictionary keys, I'd say you have to stick to round(). For example this wouldn't work:
a = 1
for x in range(5):
a += 0.1
print('%.1f' % a)
if a == 1.3:
break
1.1
1.2
1.3
1.4
1.5
You'd have to do:
a = 1
for x in range(5):
a += 0.1
print('%.1f' % a)
if round(a, 1) == 1.3:
break
1.1
1.2
1.3
Formatted output has been duly suggested by #Jaco. However, if you want control of precision in your variable beyond pure output, you might want to look at the decimal module.
from decimal import Decimal
a = 1
for x in range(3):
a += Decimal('0.10') # use string, not float as argument
# a += Decimal('0.1000')
print(a) # a is now a Decimal, not a float
> 1.10 # 1.1000
> 1.20 # 1.2000
> 1.30 # 1.3000

Python setting Decimal Place range without rounding?

How can I take a float variable, and control how far out the float goes without round()? For example.
w = float(1.678)
I want to take x and make the following variables out of it.
x = 1.67
y = 1.6
z = 1
If I use the respective round methods:
x = round(w, 2) # With round I get 1.68
y = round(y, 1) # With round I get 1.7
z = round(z, 0) # With round I get 2.0
It's going to round and alter the numbers to the point where there no use to me. I understand this is the point of round and its working properly. How would I go about getting the information that I need in the x,y,z variables and still be able to use them in other equations in a float format?
You can do:
def truncate(f, n):
return math.floor(f * 10 ** n) / 10 ** n
testing:
>>> f=1.923328437452
>>> [truncate(f, n) for n in range(7)]
[1.0, 1.9, 1.92, 1.923, 1.9233, 1.92332, 1.923328]
A super simple solution is to use strings
x = float (str (w)[:-1])
y = float (str (w)[:-2])
z = float (str (w)[:-3])
Any of the floating point library solutions would require you dodge some rounding, and using floor/powers of 10 to pick out the decimals can get a little hairy by comparison to the above.
Integers are faster to manipulate than floats/doubles which are faster than strings. In this case, I tried to get time with both approach :
timeit.timeit(stmt = "float(str(math.pi)[:12])", setup = "import math", number = 1000000)
~1.1929605630000424
for :
timeit.timeit(stmt = "math.floor(math.pi * 10 ** 10) / 10 ** 10", setup = "import math", number = 1000000)
~0.3455968870000561
So it's safe to use math.floor rather than string operation on it.
If you just need to control the precision in format
pi = 3.14159265
format(pi, '.3f') #print 3.142 # 3 precision after the decimal point
format(pi, '.1f') #print 3.1
format(pi, '.10f') #print 3.1415926500, more precision than the original
If you need to control the precision in floating point arithmetic
import decimal
decimal.getcontext().prec=4 #4 precision in total
pi = decimal.Decimal(3.14159265)
pi**2 #print Decimal('9.870') whereas '3.142 squared' would be off
--edit--
Without "rounding", thus truncating the number
import decimal
from decimal import ROUND_DOWN
decimal.getcontext().prec=4
pi*1 #print Decimal('3.142')
decimal.getcontext().rounding = ROUND_DOWN
pi*1 #print Decimal('3.141')
I think the easiest answer is :
from math import trunc
w = 1.678
x = trunc(w * 100) / 100
y = trunc(w * 10) / 10
z = trunc(w)
also this:
>>> f = 1.678
>>> n = 2
>>> int(f * 10 ** n) / 10 ** n
1.67
Easiest way to get integer:
series_col.round(2).apply(lambda x: float(str(x).split(".",1)[0]))

Categories