web-dev-qa-db-ja.com

Python整数を次の100に切り上げます

すでに何百回も要求されているはずです(しゃれは楽しい=)が、私は浮動小数点数を丸めるための関数を見つけることができます。整数を切り上げる方法、たとえば:130 -> 200

66
ofko

通常、丸めは浮動小数点数で行われますが、ここで知っておくべき3つの基本関数があります。 round (最も近い整数への丸め)、 math.floor (常に切り捨て)、および math.ceil (常に切り上げ)。

整数について質問し、数百に切り上げますが、2より小さい数であればmath.ceilを引き続き使用できます53math.ceilを使用するには、最初に100で除算し、切り上げてから100で乗算します。

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

最初に100で除算し、その後100で乗算すると、小数点以下2桁を左右に「シフト」して、math.ceilが数百で機能するようにします。数十(10**n)、数千(n = 1)などに丸めたい場合は、100ではなくn = 3を使用できます。

これを行う別の方法は、浮動小数点数(精度が制限されている)を避け、代わりに整数のみを使用することです。 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

2つのソリューションのミニベンチマークを行いました。

$ 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ソリューションと比較して2倍高速です。

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に丸めたい場合、たとえばnearest100、組み込みのround関数はあなたのためにそれを行うことができます:

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

これを試して:

int(round(130 + 49, -2))
19
Fred Foo

これは遅い答えですが、既存の答えの最良の面を組み合わせた簡単な解決策があります:xからの_100_の次の倍数は_x - x % -100_(またはお好みならx + (-x) % 100)。

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

これは高速でシンプルで、任意の整数x(John Machinの答えのような)に対して正しい結果を提供し、xがfloatの場合、合理的な結果(浮動小数点表現に関する通常の注意事項を修正)を提供します(マーティンガイスラーの答えのように)。

_>>> x = 0.1
>>> x -= x % -100
>>> x
100.0
_
19
Mark Dickinson

正の整数の最も近い倍数に切り上げる一般的な方法は次のとおりです。

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

サンプル使用法:

 >>> roundUpToMultiple(101、100)
 200 
 >>> roundUpToMultiple(654、321)
 963 
17
Luke Woodward

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
9
John Machin

Intがxの場合:_x + 100 - x % 100_

ただし、コメントで指摘されているように、これは_x==100_の場合に200を返します。

これが予期された動作でない場合は、x + 100*(x%100>0) - x%100を使用できます

3
Thomas Orozco

警告:早すぎる最適化が先に...

ここの非常に多くの答えがこれのタイミングを決めるので、私は別の選択肢を追加したかったです。

@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よりも速い理由についての説明は大歓迎です。

3
epeleg

これを試して:

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
2
Sukrit Gupta