Round with integer division

馋奶兔 提交于 2019-12-06 16:50:53

问题


Is there is a simple, pythonic way of rounding to the nearest whole number without using floating point? I'd like to do the following but with integer arithmetic:

skip = int(round(1.0 * total / surplus))

==============

@John: Floating point is not reproducible across platforms. If you want your code to pass tests across different platforms then you need to avoid floating point (or add some hacky espilon stuff to your tests and hope it works). The above may be simple enough that it would be the same on most/all platforms, but I'd rather not make that determination as it is easier to avoid floating point altogether. How is that "not in the spirit of Python"?


回答1:


You can do this quite simply:

(n + d // 2) // d, where n is the dividend and d is the divisor.

Alternatives like (((n << 1) // d) + 1) >> 1 or the equivalent (((n * 2) // d) + 1) // 2 may be SLOWER in recent CPythons, where an int is implemented like the old long.

The simple method does 3 variable accesses, 1 constant load, and 3 integer operations. The complicated methods do 2 variable accesses, 3 constant loads, and 4 integer operations. Integer operations are likely to take time which depends on the sizes of the numbers involved. Variable accesses of function locals don't involve "lookups".

If you are really desparate for speed, do benchmarks. Otherwise, KISS.




回答2:


skip = (((total << 1) // surplus) + 1) >> 1

Shifting things left by one bit effectively multiplies by two, shifting things right by one bit divides by two rounding down. Adding one in the middle makes it so that "rounding down" is actually rounding up if the result would have been above a .5 decimal part.

It's basically the same as if you wrote...

skip = int((1.0*total/surplus) + 0.5)

except with everything multplied by 2, and then later divided by 2, which is something you can do with integer arithmetic (since bit shifts don't require floating point).




回答3:


Inspired by zhmyh's answer answer, which is

q, r = divmod(total, surplus)
skip = q + int(bool(r)) # rounds to next greater integer (always ceiling)

, I came up with the following solution:

q, r = divmod(total, surplus) 
skip = q + int(2 * r >= surplus) # rounds to nearest integer (floor or ceiling)

Since the OP asked for rounding to the nearest whole number, zhmhs's solution is in fact slightly incorrect, because it always rounds to the next greater whole number, while my solution works as demanded.

(If you feel that my answer should better have been an edit or comment on zhmh's answer, let me point out that my suggested edit for it was rejected, because it should better have been a comment, but I do not have enough reputation yet for commenting!)

In case you wonder how divmod is defined: According to its documentation

For integers, the result is the same as (a // b, a % b).

We therefore stick with integer arithmetic, as demanded by the OP.




回答4:


Yet another funny way:

q, r = divmod(total, surplus)
skip = q + int(bool(r))



回答5:


Simply take care of the rounding rule before you ever divide. For the simplest round-half-up:

if total % surplus < surplus / 2:
    return total / surplus
else:
    return (total / surplus) + 1

Tweak a little bit if you need to do a proper round-to-even.




回答6:


This should work too:

def rint(n):
    return (int(n+.5) if n > 0 else int(n-.5))


来源:https://stackoverflow.com/questions/3950372/round-with-integer-division

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!