2

How do I round up a number to the next integer with a high precision?

Input: var1 = (8193/4096) # var1 = 2.00024414063
Output: 3 # As an integer

>>> var1 = 8193/4096
>>> import math
>>> math.ceil(var1)
2.0
>>> math.ceil(8193/4096)
2.0
>>> import numpy
>>> numpy.ceil(8193/4096)

How can I elegantly do this operation?

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
0x0
  • 2,915
  • 5
  • 40
  • 67

4 Answers4

4

In Python 2, this:

>>> var1 = 8193/4096

doesn't do what you think it does. In Python 2, dividing two integers always returns an integer (truncated) as the result.

>>> 8193/4096
2

...and then calling math.ceil() on 2 returns 2.

Convert one or both of your values to a floating point value and it will do what you like:

>>> v = 8193/4096.0
>>> v
2.000244140625
>>> math.ceil(v)
3.0

Alternatives:

a) switch to Python 3, where division does behave like you want it to:

bgporter@zappa:~$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:18)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 8193/4096
2.000244140625
>>>

b) enable Python 3's division on Python 2 like this:

bgporter@varese ~:python
Python 2.7.5 (default, Mar  9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from __future__ import division
>>> 8193/4096
2.000244140625
bgporter
  • 35,114
  • 8
  • 59
  • 65
2

Issue: You are currently doing integer division, which would implicitly compute the floor of the quotient and give you the Integer value.

Solution: Cast one of the elements (divisor or dividend) to a float first:

math.ceil( float(8193)/4096 ) 
3.0

OR: just make it a float by adding .0 to the end of one of the numbers, like so:

math.ceil( 8193.0/4096 )
3.0

OR: import division feature from the __future__ module to allow Python 3 division by default:

from __future__ import division
math.ceil( 8193.0/4096 )

Python 3: In Python 3, however, / is the true division, so you don't have to worry about above. There, if you want to replicate the issue that you are encountering, you would have to use // for the integer division. // functionality is the same across all Python version.

Pacific Stickler
  • 1,078
  • 8
  • 20
2
-(-8193/4096)

does exact integer division, and rounds upwards.

It's thus way better than involving floats.

It's simply because a/b floors, so -a/b floors the negative, so -(-a/b) gives you the answer you want.

To support Python 3 (always a good idea), use -(-8193//4096).


Here's a quick example where it beats out ceil:

>>> -(-10**17 // 3)
33333333333333334
>>> int(ceil(10**17 / 3.0))
33333333333333332
Veedrac
  • 58,273
  • 15
  • 112
  • 169
  • I retract my previous criticism -- I'd missed that this was Python2. However this smacks of arcane symbols rather than pythonic programming. This is along the same lines of using `~~some_int` instead of `abs(some_int)` – Adam Smith Sep 10 '14 at 20:51
  • Note that `//` works in Python 2 as well. – DSM Sep 10 '14 at 20:51
  • @AdamSmith `~~x` just gives `x`... Anyhow, I agree **but** it's sufficiently better than using floats that it's better to just wrap it in a function or comment it and live with the potential confusion. :) – Veedrac Sep 10 '14 at 20:53
  • @Veedrac oops you're right, `~~x` is `floor(x)` not `abs(x)`. – Adam Smith Sep 10 '14 at 20:54
  • I strongly disagree with this approach. Premature optimization by introducing arcane double negation is the exact opposite of the kind of code I want to write (or maintain) – Adam Smith Sep 10 '14 at 20:58
  • @AdamSmith Optimisation? I'm doing this for correctness. I find it easier to prove than Anton Savin's method because the edge cases are obvious. – Veedrac Sep 10 '14 at 21:02
  • Well, since the equivalent answer in the other question got lots of upvotes too, I guess we're not alone in liking this approach. :-) – DSM Sep 10 '14 at 21:15
1

Another pure integer way, for me a bit more intuitive than the approach with double negation, though it works only for positive y:

def myceil(x, y):
    return (x + y - 1) // y
Anton Savin
  • 40,838
  • 8
  • 54
  • 90