I\'ve been trying to round long float numbers like:
32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...
With no success so far. I
If you need (for example) a two digit approximation for A, then
int(A*100+0.5)/100.0
will do what you are looking for.
If you need three digit approximation multiply and divide by 1000 and so on.
int(round(x))
Will round it and change it to integer
EDIT:
You are not assigning int(round(h)) to any variable. When you call int(round(h)), it returns the integer number but does nothing else; you have to change that line for:
h = int(round(h))
To assign the new value to h
EDIT 2:
As @plowman said in the comments, Python's round()
doesn't work as one would normally expect, and that's because the way the number is stored as a variable is usually not the way you see it on screen. There are lots of answers that explain this behavior:
round() doesn't seem to be rounding properly
One way to avoid this problem is to use the Decimal as stated by this answer: https://stackoverflow.com/a/15398691/4345659
In order for this answer to work properly without using extra libraries it would be convenient to use a custom rounding function. After a lot of corrections, I came up with the following solution, that as far as I tested avoided all the storing issues. It is based on using the string representation, obtained with repr()
(NOT str()
!). It looks hacky but it was the only way I found to solve all the cases. It works with both Python2 and Python3.
def proper_round(num, dec=0):
num = str(num)[:str(num).index('.')+dec+2]
if num[-1]>='5':
return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
return float(num[:-1])
Tests:
>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>>
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0
Finally, the corrected answer would be:
# Having proper_round defined as previously stated
h = int(proper_round(h))
EDIT 3:
Tests:
>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1 # should be 7
The gotcha here is that the dec
-th decimal can be 9 and if the dec+1
-th digit >=5 the 9 will become a 0 and a 1 should be carried to the dec-1
-th digit.
If we take this into consideration, we get:
def proper_round(num, dec=0):
num = str(num)[:str(num).index('.')+dec+2]
if num[-1]>='5':
a = num[:-2-(not dec)] # integer part
b = int(num[-2-(not dec)])+1 # decimal part
return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
return float(num[:-1])
In the situation described above b = 10
and the previous version would just concatenate a
and b
which would result in a concatenation of 10
where the trailing 0 would disappear. This version transforms b
to the right decimal place based on dec
, as a proper carry.
You can also use numpy assuming if you are using python3.x here is an example
import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
Isn't just Python doing round half to even, as prescribed by IEEE 754?
Be careful redefining, or using "non-standard" rounding…
(See also https://stackoverflow.com/a/33019948/109839)
round(value,significantDigit)
is the ordinary solution, however this does not operate as one would expect from a math perspective when round values ending in 5
. If the 5
is in the digit just after the one you're rounded to, these values are only sometimes rounded up as expected (i.e. 8.005
rounding to two decimal digits gives 8.01
). For certain values due to the quirks of floating point math, they are rounded down instead!
i.e.
>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01
Weird.
Assuming your intent is to do the traditional rounding for statistics in the sciences, this is a handy wrapper to get the round
function working as expected needing to import
extra stuff like Decimal
.
>>> round(0.075,2)
0.07
>>> round(0.075+10**(-2*5),2)
0.08
Aha! So based on this we can make a function...
def roundTraditional(val,digits):
return round(val+10**(-len(str(val))-1), digits)
Basically this adds a value guaranteed to be smaller than the least given digit of the string you're trying to use round
on. By adding that small quantity it preserve's round
's behavior in most cases, while now ensuring if the digit inferior to the one being rounded to is 5
it rounds up, and if it is 4
it rounds down.
The approach of using 10**(-len(val)-1)
was deliberate, as it the largest small number you can add to force the shift, while also ensuring that the value you add never changes the rounding even if the decimal .
is missing. I could use just 10**(-len(val))
with a condiditional if (val>1)
to subtract 1
more... but it's simpler to just always subtract the 1
as that won't change much the applicable range of decimal numbers this workaround can properly handle. This approach will fail if your values reaches the limits of the type, this will fail, but for nearly the entire range of valid decimal values it should work.
You can also use the decimal library to accomplish this, but the wrapper I propose is simpler and may be preferred in some cases.
Edit: Thanks Blckknght for pointing out that the 5
fringe case occurs only for certain values. Also an earlier version of this answer wasn't explicit enough that the odd rounding behavior occurs only when the digit immediately inferior to the digit you're rounding to has a 5
.