# Round number to nearest integer

**TL;DR:**

`int(round(x))`

Will round it and change it to integer

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`

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.

One way to avoid this problem is to use the Decimal as stated by this answer.

In order for this answer to work properly without using extra libraries it would be convenient to use a custom rounding function. 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 statedh = int(proper_round(h))`

**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.

Use `round(x, y)`

. It will round up your number up to your desired decimal place.

For example:

`>>> round(32.268907563, 3)32.269`

`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*.