Dowiedziałem się o //
operatorze w Pythonie, który w Pythonie 3 dzieli się na podłogę.
Czy istnieje operator, który zamiast tego dzieli się na ceil? (Wiem o /
operatorze, który w Pythonie 3 wykonuje dzielenie zmiennoprzecinkowe).
Dowiedziałem się o //
operatorze w Pythonie, który w Pythonie 3 dzieli się na podłogę.
Czy istnieje operator, który zamiast tego dzieli się na ceil? (Wiem o /
operatorze, który w Pythonie 3 wykonuje dzielenie zmiennoprzecinkowe).
Odpowiedzi:
Nie ma operatora, który dzieli górą. Musisz import math
i używaćmath.ceil
Możesz po prostu wykonać podział piętra do góry nogami:
def ceildiv(a, b):
return -(-a // b)
Działa to, ponieważ operator dzielenia w Pythonie wykonuje dzielenie na podłogę (w przeciwieństwie do C, gdzie dzielenie całkowite obcina część ułamkową).
Działa to również z dużymi liczbami całkowitymi Pythona, ponieważ nie ma (stratnej) konwersji zmiennoprzecinkowej.
Oto demonstracja:
>>> from __future__ import division # a/b is float division
>>> from math import ceil
>>> b = 3
>>> for a in range(-7, 8):
... print(["%d/%d" % (a, b), int(ceil(a / b)), -(-a // b)])
...
['-7/3', -2, -2]
['-6/3', -2, -2]
['-5/3', -1, -1]
['-4/3', -1, -1]
['-3/3', -1, -1]
['-2/3', 0, 0]
['-1/3', 0, 0]
['0/3', 0, 0]
['1/3', 1, 1]
['2/3', 1, 1]
['3/3', 1, 1]
['4/3', 2, 2]
['5/3', 2, 2]
['6/3', 2, 2]
['7/3', 3, 3]
int
nie (no cóż, żadnych znaczących; w 64-bitowym Pythonie jesteś ograniczony do 30 * (2**63 - 1)
liczb bitowych), a nawet tymczasowa konwersja na float
może utracić informacje. Porównaj math.ceil((1 << 128) / 10)
z -(-(1 << 128) // 10)
.
Można to zrobić (x + (d-1)) // d
dzieląc x
przez d
, tj (x + 4) // 5
.
sys.float_info.max
i nie wymaga importu.
def ceiling_division(n, d):
return -(n // -d)
Przypomina sztuczkę lewitacji Penn & Teller , która „odwraca świat do góry nogami (z negacją), wykorzystuje zwykły podział podłogi (gdzie zamieniono sufit i podłogę), a następnie obraca świat w prawą stronę (ponownie z negacją) "
def ceiling_division(n, d):
q, r = divmod(n, d)
return q + bool(r)
Funkcja divmod () podaje (a // b, a % b)
liczby całkowite (może to być mniej niezawodne w przypadku wartości zmiennoprzecinkowych z powodu błędu zaokrąglenia). Krok z bool(r)
dodaje jedynkę do ilorazu za każdym razem, gdy pozostaje niezerowa reszta.
def ceiling_division(n, d):
return (n + d - 1) // d
Przesuń licznik w górę, aby podział podłogi został zaokrąglony w dół do przewidywanego sufitu. Uwaga, działa to tylko dla liczb całkowitych.
def ceiling_division(n, d):
return math.ceil(n / d)
Kod math.ceil () jest łatwy do zrozumienia, ale konwertuje z liczb całkowitych na zmiennoprzecinkowe iz powrotem. Nie jest to zbyt szybkie i może powodować problemy z zaokrąglaniem. Opiera się również na semantyce Pythona 3, gdzie „prawdziwy podział” tworzy liczbę zmiennoprzecinkową, a funkcja ceil () zwraca liczbę całkowitą.
-(-a // b)
o_O
-(a // -b)
jest szybszy niż -(-a // b)
, przynajmniej jeśli chodzi o synchronizację przykładów zabawek zpython -m timeit ...
Zawsze możesz to również zrobić w trybie inline
((foo - 1) // bar) + 1
W pythonie3 jest to o rząd wielkości szybsze niż wymuszanie dzielenia typu float i wywoływanie ceil (), pod warunkiem, że zależy Ci na szybkości. Czego nie powinieneś, chyba że udowodniłeś poprzez użycie, że musisz.
>>> timeit.timeit("((5 - 1) // 4) + 1", number = 100000000)
1.7249219375662506
>>> timeit.timeit("ceil(5/4)", setup="from math import ceil", number = 100000000)
12.096064013894647
number=100000000
). W przypadku pojedynczego połączenia różnica jest niewielka.
foo = -8
i bar = -4
, na przykład, odpowiedź powinna wynosić 2, a nie 3, tak jak -8 // -4
. Podział podłogi w Pythonie jest definiowany jako „podział matematyczny z funkcją„ podłogi ”zastosowaną do wyniku”, a podział sufitu jest tym samym, ale z ceil()
zamiast floor()
.
Zauważ, że math.ceil jest ograniczona do 53 bitów precyzji. Jeśli pracujesz z dużymi liczbami całkowitymi, możesz nie uzyskać dokładnych wyników.
Gmpy2 Libary zapewnia c_div
funkcję zaokrąglania, który wykorzystuje na suficie.
Zastrzeżenie: utrzymuję gmpy2.
python2 -c 'from math import ceil;assert ceil(11520000000000000102.9)==11520000000000000000'
(jak również zastępowanie python3
) True
Proste rozwiązanie: a // b + 1