2012-01-14 65 views
43

Có vẻ như nó đã được hỏi hàng trăm lần (số lần chơi chữ là vui) = nhưng tôi chỉ có thể tìm thấy hàm cho làm tròn phao. Làm cách nào để làm tròn số nguyên, ví dụ: 130 -> 200?Python làm tròn số nguyên lên hàng trăm

+0

Bạn có muốn 100 được làm tròn tới 200 không? – DSM

+0

Không, câu trả lời của Thomas chỉ là những gì tôi cần – ofko

+0

Câu trả lời của Thomas * * tròn 100 đến 200. Đó là lý do tôi hỏi. – DSM

Trả lời

78

làm tròn thường được thực hiện trên số dấu chấm động, và ở đây có ba chức năng cơ bản bạn nên biết: round (vòng số nguyên gần nhất), math.floor (luôn luôn làm tròn) và math.ceil (luôn luôn làm tròn).

Bạn hỏi về số nguyên và làm tròn lên đến hàng trăm, nhưng chúng tôi vẫn có thể sử dụng math.ceil miễn là số của bạn nhỏ hơn 2 . Để sử dụng math.ceil, chúng tôi chỉ chia cho 100 đầu tiên, tròn, và nhân với 100 sau:

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

Dividing bởi 100 đầu tiên và nhân với 100 sau đó "chuyển" hai chữ số thập phân sang bên phải và bên trái để math.ceil hoạt động trên hàng trăm. Bạn có thể sử dụng 10**n thay vì 100 nếu bạn muốn làm tròn tới hàng chục (n = 1), hàng nghìn (n = 3), v.v.

Cách khác là tránh các số dấu phẩy động (chúng có độ chính xác giới hạn) và thay vào đó sử dụng chỉ số nguyên. Các số nguyên có độ chính xác tùy ý bằng Python, do đó, số này cho phép bạn làm tròn số bất kỳ kích thước nào. Các quy tắc cho làm tròn rất đơn giản: tìm phần còn lại sau khi chia 100, và thêm 100 trừ đi phần còn lại này nếu nó khác không:

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

này làm việc cho số của bất kỳ kích thước:

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

tôi đã làm một điểm chuẩn nhỏ của hai giải pháp:

$ 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 

Giải pháp nguyên gốc nhanh hơn hai lần so với giải pháp math.ceil.

Thomas đề xuất một giải pháp dựa trên số nguyên giống với giải pháp tôi có ở trên, ngoại trừ việc nó sử dụng một thủ thuật bằng cách nhân các giá trị Boolean. Thật thú vị khi thấy rằng không có lợi thế tốc độ viết mã theo cách này:

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

Như một nhận xét cuối cùng, hãy để tôi cũng lưu ý rằng nếu bạn đã muốn làm tròn 101-149 đến 100 và 150 vòng –199 đến 200, ví dụ, Vòng đến gần trăm, sau đó được xây dựng trong round chức năng có thể làm điều đó cho bạn:

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

Tôi không làm tròn bình thường ở đây, nếu tôi có, tôi sẽ sử dụng vòng() – ofko

+3

@ofko: đúng, bạn muốn làm tròn lên. 'Math.ceil' là cách kinh điển để làm điều đó - chia và nhân với 100 là cách kinh điển để làm cho' round', 'ceil', và' floor' hoạt động trên hàng trăm. –

+1

Sau các chỉnh sửa gần đây, bây giờ bạn nên chấp nhận câu trả lời này. – ofko

13

Hãy thử điều này:

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

Nếu int của bạn là x: x + 100 - x % 100

Tuy nhiên, khi chỉ trong ý kiến, điều này sẽ trở lại 200 nếu x==100.

Nếu đây không phải là hành vi mong đợi, bạn có thể sử dụng x + 100*(x%100>0) - x%100

+0

Điều gì xảy ra nếu 'x' đã là bội số của 100? –

+0

Bạn có thể muốn sử dụng các giải pháp khác nếu bạn không thích số ma thuật. Nếu bạn quan tâm đến hiệu suất, điều này tuy nhiên chạy nhanh hơn. –

+0

@LukeWoodward Điểm tuyệt vời, tôi sẽ chỉnh sửa –

17

Dưới đây là một cách tổng quát về làm tròn đến bội số gần nhất của bất kỳ số nguyên dương:

def roundUpToMultiple(number, multiple): 
    num = number + (multiple - 1) 
    return num - (num % multiple) 
sử dụng

mẫu:

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

quá phức tạp –

+0

tương đương, phương pháp ngắn hơn: 'lambda number, multiple: multiple * (1 + (number - 1) // multiple)' –

8

Đối a không âm, b Posi chính kịp thời, cả hai số nguyên:

>>> 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)] 

Cập nhậtCâu trả lời hiện đang chấp nhận sụp đổ với số nguyên như vậy mà float (x)/float (y) không thể được đại diện một cách chính xác như một float. Xem mã này:

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__ 

Output:

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 

Và đây là một số timings:

>\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 
+0

'Tôi biết OP là làm tròn số nguyên' - nhưng tôi muốn chỉ ra rằng bạn sẽ cố gắng sử dụng 3 tùy chọn trên (0,5,10) mà tôi mong đợi trả về 10 thì hai phương thức đầu tiên (geisler & orozco) trả về 10 như mong đợi trong khi machin trả về 0 – epeleg

12

Đây là một câu trả lời muộn, nhưng có một giải pháp đơn giản mà kết hợp các khía cạnh tốt nhất của câu trả lời hiện có: số nhiều tiếp theo của 100 từ số xx - x % -100 (hoặc nếu bạn thích, x + (-x) % 100).

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

này là nhanh chóng và đơn giản, cho kết quả chính xác cho bất kỳ số nguyên x (như câu trả lời John Machin) và cũng cho kết quả hợp lý-ish (modulo hãy cẩn thận thông thường về đại diện dấu chấm động) nếu x là một phao (như câu trả lời của Martin Geisler).

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

giải pháp của bạn nhanh như ký hiệu của Martin nhưng ngắn hơn. cảm ơn. % thời gian 'x = 110' 'x - = x% -100' # 100000000 vòng, tốt nhất là 3: 9,37 ns trên mỗi vòng VS % timeit 'x = 110' 'x + 100 * (x% 100> 0) - x% 100 ' # 100000000 vòng, tốt nhất là 3: 9,38 ns trên mỗi vòng lặp – tagoma

1

Hãy thử điều này: sử dụng

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 

mẫu:

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

Cảnh báo: tối ưu hóa sớm về phía trước ...

Vì có quá nhiều các câu trả lời ở đây làm thời gian của điều này tôi muốn thêm một giải pháp thay thế khác.

Lấy @ Martin Geisler 's

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

(mà tôi thích nhất vì nhiều lý do)

nhưng bao thanh toán ra hành động%

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

mang lại một sự cải thiện tốc độ ~ 20% trên bản gốc

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

Thậm chí còn tốt hơn và nhanh hơn ~ 36% thì

cuối cùng tôi đã suy nghĩ rằng mình có thể bỏ toán tử not và thay đổi thứ tự của các chi nhánh, hy vọng điều này cũng sẽ tăng tốc độ. nó thực sự là chậm hơn giảm trở lại chỉ nhanh hơn 23% sau đó ban đầu.

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 

giải thích tại sao 3 nhanh hơn sau đó 4 sẽ được chào đón nhiều nhất.

Các vấn đề liên quan