Python将整数舍入到下一百


78

似乎应该已经被问过数百次了(双关很有趣=),但是我只能找到舍入浮点数的函数。如何围捕一个整数,例如:130 -> 200


3
您是否还希望将100舍入为200?
DSM

不,托马斯的答案正是我所需要的
userBG 2012年

1
托马斯的回答确实轮100到200,这就是为什么我问。
DSM 2012年

检查编辑,在第一个答案中我没有注意。
Thomas Orozco 2012年

1
@ofko:您接受了以大整数失败的答案;有关详细信息,请参见我更新的答案。
约翰·马钦

Answers:


148

四舍五入通常是对浮点数进行的,这里您应该了解三个基本函数:(round四舍五入到最接近的整数),math.floor(总是四舍五入)和math.ceil(总是四舍五入)。

您询问整数并舍入到数百,但是math.ceil只要您的数字小于2 53,我们仍然可以使用。要使用math.ceil,我们只需先除以100,向上舍入,然后再乘以100:

>>> import math
>>> def roundup(x):
...     return int(math.ceil(x / 100.0)) * 100
... 
>>> roundup(100)
100
>>> roundup(101)
200

先除以100,然后再乘以100,然后将“小数点”向左和向右移动两位,这样就math.ceil可以处理数百个数字。10**n如果您想舍入到十(n = 1),数千(n = 3)等,可以使用而不是100 。

执行此操作的另一种方法是避免浮点数(精度有限),而仅使用整数。整数在Python中具有任意精度,因此可以四舍五入任意大小的数字。四舍五入的规则很简单:除以100后找到余数,如果非零则加100减去此余数:

>>> def roundup(x):
...     return x if x % 100 == 0 else x + 100 - x % 100

这适用于任何大小的数字:

>>> roundup(100)
100
>>> roundup(130)
200
>>> roundup(1234567891234567891)
1234567891234567900L

我对这两种解决方案做了一个迷你基准测试:

$ python -m timeit -s 'import math' -s 'x = 130' 'int(math.ceil(x/100.0)) * 100'
1000000 loops, best of 3: 0.364 usec per loop
$ python -m timeit -s 'x = 130' 'x if x % 100 == 0 else x + 100 - x % 100'
10000000 loops, best of 3: 0.162 usec per loop

与该math.ceil解相比,纯整数解的速度快两倍。

Thomas提出了一种基于整数的解决方案,该解决方案与我上面的解决方案完全相同,不同之处在于它通过将布尔值相乘来使用技巧。有趣的是,以这种方式编写代码没有速度优势:

$ python -m timeit -s 'x = 130' 'x + 100*(x%100>0) - x%100'
10000000 loops, best of 3: 0.167 usec per loop

最后,请允许我注意一下,如果您想将101–149舍入到100,并将150–199舍入到200,例如,舍入到最接近的百位,则内置round函数可以为您做到这一点:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200

我没有在这里进行正常的舍入,如果是的话,我将使用round()
userBG 2012年

3
@ofko:对,您想四舍五入。该math.ceil是做了规范的方法-将乘以100是使规范的方法roundceil以及floor数以百计的工作。
马丁·盖斯勒

1
经过最近的编辑后,现在可以接受此答案了。
userBG 2012年

2
-1这种方法对浮点数可能是“规范的”,但对大整数则失败。有关详细信息,请参见我的答案。OP特别要求提供整数,并且不表示数字大小的上限。
约翰·马钦

1
@JohnMachin:反对票是针对“无用”的问题的,我无法理解为什么这个简单而直接的答案没有用。逸岸,在OP将其标记为接受,因此它有用的。此外,当有人需要帮助将130舍入到200时,我认为抱怨不能正确舍入1234567891234567891有点麻烦。没错,floatlong(当然!)相比,精确度是有限的,但是对于大多数实际情况而言,afloat足够大。
马丁·盖斯勒

26

这是一个迟到的回答,但有一个简单的解决方案,结合了现有的答案的最好方面的下一个倍数100最多的xx - x % -100(或者,如果你喜欢,x + (-x) % 100)。

>>> x = 130
>>> x -= x % -100  # Round x up to next multiple of 100.
>>> x
200

这是快速而简单的,可以给出任何整数的正确结果x(例如John Machin的答案),并且如果x是浮点数(例如Martin Geisler的答案),也可以给出合理的结果(对浮点表示法的常见警告进行模运算)。

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0

1
您的解决方案与Martin一样快,但符号更短。谢谢。%timeit'x = 110''x-= x%-100'#100000000循环,每循环最好3:9.37 ns VS%timeit'x = 110''x + 100 *(x%100> 0)-x %100'#100000000循环,每循环3:9.38 ns最佳
塔格玛,

21

试试这个:

int(round(130 + 49, -2))

为什么要int()?type(round(999,-2))是int(python 3.8)
Tim Richardson

但是,这并不总是四舍五入,这就是问题所在。
蒂姆

18

这是舍入到任何正整数的最接近倍数的一般方法:

def roundUpToMultiple(number, multiple):
    num = number + (multiple - 1)
    return num - (num % multiple)

用法示例:

>>> roundUpToMultiple(101,100)
200
>>> roundUpToMultiple(654,321)
963

等价的较短方法:lambda number, multiple: multiple * (1 + (number - 1) // multiple)
mic_e 2014年

8

对于a非负,b正两个整数:

>>> rup = lambda a, b: (a + b - 1) // b * b
>>> [(x, rup(x, 100)) for x in (199, 200, 201)]
[(199, 200), (200, 200), (201, 300)]

更新 当前接受的答案与整数分开,以致无法将float(x)/ float(y)准确地表示为float。参见以下代码:

import math

def geisler(x, y): return int(math.ceil(x / float(y))) * y

def orozco(x, y): return x + y * (x % y > 0) - x % y

def machin(x, y): return (x + y - 1) // y * y

for m, n in (
    (123456789123456789, 100),
    (1234567891234567891, 100),
    (12345678912345678912, 100),
    ):
    print; print m, "m"; print n, "n"
    for func in (geissler, orozco, machin):
        print func(m, n), func.__name__

输出:

123456789123456789 m
100 n
123456789123456800 geisler
123456789123456800 orozco
123456789123456800 machin

1234567891234567891 m
100 n
1234567891234568000 geisler <<<=== wrong
1234567891234567900 orozco
1234567891234567900 machin

12345678912345678912 m
100 n
12345678912345680000 geisler <<<=== wrong
12345678912345679000 orozco
12345678912345679000 machin

以下是一些时间安排:

>\python27\python -m timeit -s "import math;x =130" "int(math.ceil(x/100.0))*100"
1000000 loops, best of 3: 0.342 usec per loop

>\python27\python -m timeit -s "x = 130" "x + 100 * (x % 100 > 0) - x % 100"
10000000 loops, best of 3: 0.151 usec per loop

>\python27\python -m timeit -s "x = 100" "(x + 99) // 100 * 100"
10000000 loops, best of 3: 0.0903 usec per loop

I know the OP was about rounding an integer-但我想指出的是,您将尝试在(0.5,10)上使用这3个选项,我希望它们返回10,然后前两个方法(geisler和orozco)按预期返回10,而
machin

3

如果您的int是x: x + 100 - x % 100

但是,正如注释中指出的那样,如果返回,则将返回200 x==100

如果这不是预期的行为,则可以使用 x + 100*(x%100>0) - x%100


如果您不喜欢魔术数字,则可能要使用其他解决方案。如果您担心性能,则运行速度会更快。
Thomas Orozco 2012年

是的,不应该对100进行四舍五入,但是如果那样会使公式变得过于复杂,我可以防止使用代码,别无用
userBG 2012年

好吧,另一个版本解决了这个问题,因为它包括加100之前的检查!如果这满足您的需求,请别忘了接受!:)
Thomas Orozco'1

1
抱歉,但是我发现此代码非常不符合Python规范。是的,abool具有数值,所以可以,您可以将其与布尔表达式相乘。但是其他解决方案更加清晰。
马丁·盖斯勒

好吧,我确实指出,如果性能不是关键参数,则可以首选其他代码。
Thomas Orozco 2012年

3

试试这个:

import math
def ceilm(number,multiple):
    '''Returns a float rounded up by a factor of the multiple specified'''
    return math.ceil(float(number)/multiple)*multiple

用法示例:

>>> ceilm(257,5)
260
>>> ceilm(260,5)
260

3

警告:过早的优化...

由于此处的答案很多,因此我想添加另一种选择。

以@Martin Geisler的

def roundup(x):
    return x if x % 100 == 0 else x + 100 - x % 100

(由于几个原因,我最喜欢)

但排除%操作

def roundup2(x):
    x100= x % 100
    return x if x100 == 0 else x + 100 - x100

与原始速度相比,速度提高约20%

def roundup3(x):
    x100 = x % 100
    return x if not x100 else x + 100 - x100

甚至更好,比原始速度快36%

最终,我以为我可以删除not运算符并更改分支的顺序,希望这样做也可以提高速度,但困惑于发现它实际上更慢,回落到仅比原始速度快23%。

def roundup4(x):
    x100 = x % 100
    return x + 100 - x100  if x100 else x


>python -m timeit -s "x = 130" "x if x % 100 == 0 else x + 100 - x % 100"
1000000 loops, best of 3: 0.359 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if x100 == 0 else x + 100 - x100"
1000000 loops, best of 3: 0.287 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if not x100 else x + 100 - x100"
1000000 loops, best of 3: 0.23 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x + 100 - x100 if x100 else x"
1000000 loops, best of 3: 0.277 usec per loop

关于为什么3快于4的解释将是最受欢迎的。


0

这是一个非常简单的解决方案:

next_hundred = x//100*100+100

它是如何工作的?

  1. 用100进行整数除法(它基本上切除了正常除法的小数部分)。这样,您可以获得数的十。例如:243 // 100 = 2。
  2. 乘以100,得到的原始数字不包含十进制和一个。例如:2 * 100 = 200。
  3. 加100可获得所需结果。例如:200 + 100 = 300

一些例子

  • 0 ... 99舍入为100
  • 100 ... 199舍入为200
  • 等等

稍作修改的方法将1 ... 100舍入为100,将101 ... 200舍入为200等..

next_hundred = (x-1)//100*100+100
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.