Python'da // operatörünün tavan eşdeğeri var mı?


128

//Python'daki operatörü Python 3'te yerle bölme yapan Python'da öğrendim .

Bunun yerine tavanla bölünen bir operatör var mı? ( /Python 3'te kayan nokta bölme yapan operatörü biliyorum .)


1
Önemli: int veya float sonucu mu istiyorsunuz?
smci

10
Kabul edilen yanıtı dlitz'e değiştirmelisiniz. math.ceil yüzer içindir, Python'un keyfi hassasiyetli uzun inçleri ile çalışmaz.
endolith

2
@milllimoose Soru geçerlidir, çünkü 1) "tavan bölmesi" aynı zamanda "modüllü bölme" ye dayanmaktadır, 2) matematik gerçekten neyin yaygın olduğunu ve neyin olmadığını söylemiyor, 3) "sürekli bölme için bu işleme ihtiyacınız var paketleme sorunu ", yani $ n $ öğeyi paketlemek için $ k $ boyutunda kaç kutuya ihtiyaç vardır.
Tomasz Gandor

Yanıtlar:


55

Tavana bölünen operatör yoktur. İhtiyacın var import mathve kullanmalısınmath.ceil


so foobar = math.ceil (foo / bar)? Hmm, bununla yaşayabilirim, bunu kullanmak istediğim yeri bilmiyorum, sadece merak
ettim

37
–1 kullanmayın , bu çok büyük tamsayılar için başarısız olmaya başlayacaktır. Bu yaklaşımla çok duyarlıklı bir aritmetik kitaplık kullanın veya tamsayı alanında kalın .
wim

5
kesinlikle tamsayı alanında kalın. bunun daha performanslı ve daha az baş ağrısı olduğu neredeyse garantidir .
Samy Bencherif

1
@David 天宇 Wong gmpy2 (burada başka bir cevapta bahsedilmiştir) iyidir.
wim

1
Math.ceil'in 53 bitlik hassasiyetle sınırlı olduğunu unutmayın. Büyük tam sayılarla çalışıyorsanız, kesin sonuçlar alamayabilirsiniz.
techkuz

292

Sadece baş aşağı kat bölme yapabilirsiniz:

def ceildiv(a, b):
    return -(-a // b)

Bu işe yarar çünkü Python'un bölme operatörü kat bölme yapar (tamsayı bölmenin kesirli bölümü kestiği C'nin aksine).

Bu aynı zamanda Python'un büyük tam sayılarıyla da çalışır, çünkü (kayıplı) kayan nokta dönüşümü yoktur.

İşte bir gösteri:

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

2
@apadana Bunun çok akıllıca olduğunu kabul ediyorum, ancak çok okunaklı ve bakımı zor değil! Matematikten ceil'i almaya karar verdim, böylece meslektaşlarımdan biri kod satırımı okuduğunda ne yaptığını anlayacak!
SlimCheney

2
@apadana Katılmıyorum. Soru, Python'da "bunun için" bir operatör "olup olmadığını sordu. Yanıtlara göre yanıt "hayır" olarak görünüyor. Yine de Dlitz'in cevabını yararlılığı için yükseltiyorum.
Ana Nimbus

12
@SlimCheney Bu yöntemi belgelenmiş bir işleve atın ve gitmeniz iyi olur. Tek bir süpürme hareketinde performans + okunabilirlik.
Samy Bencherif

2
@SamyBencherif: Sadece performans + okunabilirlik değil, aynı zamanda büyük girdiler için doğruluk; kayan noktanın temsil sınırlamaları varken, Python'un intsahip olmadığı (iyi, anlamlı olanları yok; 64 bit Python'da 30 * (2**63 - 1)bit sayılarıyla sınırlısınız) ve hatta geçici olarak dönüştürmek floatbilgi kaybedebilir. Karşılaştırma math.ceil((1 << 128) / 10)için -(-(1 << 128) // 10).
ShadowRanger

1
Bu sadece standart kitaplığa dahil edilmelidir
endolith

26

Sen yapabileceğini (x + (d-1)) // dbölünürken, xtarafından dyani (x + 4) // 5.


2
Bu, sonsuza dek kullandığım klasik yöntem. Negatif bölenler için işe yaramıyor.
Mark Ransom

Ürettiği aynı sonucu olarak math.ceil().
Abhijeet

3
@Abhijeet Evet, sorunun sorduğu şey bu. Yukarıdaki büyük tamsayılar için daha iyi çalışması dışında sys.float_info.maxve içe aktarma gerektirmez.
Artyer

23

1.Çözüm: Negatif bir şekilde zemini tavana dönüştürün

def ceiling_division(n, d):
    return -(n // -d)

Penn & Teller havaya yükselme hilesini anımsatan bu "dünyayı ters çevirir (olumsuzlukla), düz zemin bölmesini kullanır (tavan ve zeminin değiştirildiği yerde) ve sonra dünyayı sağ tarafa çevirir (tekrar olumsuzla) "

2.Çözüm: İşi divmod () yapsın

def ceiling_division(n, d):
    q, r = divmod(n, d)
    return q + bool(r)

Divmod () fonksiyonu verir (a // b, a % b)(bu durum yuvarlama hatası yüzdürücülü az güvenilir olabilir) tamsayılar için. İle adım, bool(r)sıfır olmayan bir kalan olduğunda bölüme bir ekler.

3. Çözüm: Bölmeden önce payı ayarlayın

def ceiling_division(n, d):
    return (n + d - 1) // d

Payı yukarı doğru çevirin, böylece kat bölmesi istenen tavana yuvarlanır. Bunun yalnızca tam sayılar için işe yaradığını unutmayın.

4.Çözüm: math.ceil () kullanmak için kayan değerlere dönüştürün

def ceiling_division(n, d):
    return math.ceil(n / d)

Math.ceil () kodu anlamak kolay, ancak yüzen ve arkaya ints gelen dönüştürür. Bu çok hızlı değil ve yuvarlama sorunları olabilir. Ayrıca, "true division" ın bir float ürettiği ve ceil () fonksiyonunun bir tamsayı döndürdüğü Python 3 semantiğine dayanır .


2
Hızlı testlerde, # 1, -(-a // b)o_O ile karşılaştırıldığında bile en hızlısı
endolith

Burada bunu doğrulamak , en azından oyuncak örneklerini zamanlarken olduğundan -(a // -b)daha hızlı-(-a // b)python -m timeit ...
Jasha

19

Her zaman sadece satır içi olarak da yapabilirsiniz

((foo - 1) // bar) + 1

Python3'te, bu, hızı önemsediğiniz sürece float bölümünü zorlamaktan ve ceil () 'i çağırmaktan daha hızlıdır. Gereksinim duyduğunuz kullanım yoluyla kanıtlamadıkça, yapmamalısınız.

>>> timeit.timeit("((5 - 1) // 4) + 1", number = 100000000)
1.7249219375662506
>>> timeit.timeit("ceil(5/4)", setup="from math import ceil", number = 100000000)
12.096064013894647

12.5 saniye aldığım testleri kendim yaptım, ehrm, bu kadar büyük bir hız farkı varken neden hıza aldırmayayım?
Cradam

3
@Cradam 100 milyon çağrı yaptığını unutmayın ( number=100000000). Tek aramada fark oldukça önemsizdir.
Rushy Panchal

4
Çünkü kod netliği her şeyden üstündür. Muhtemelen bu durumda netlik nesneldir. Ancak her zaman önce okunabilir / bakımı yapılabilir hale getirmelisiniz. Ne zaman ve sadece bir performans kontrol noktası keşfettiğinizde, kuralları çiğniyorsunuz. Modern makineler çok hızlıdır ve programınızın yaptığı diğer tüm şeyler, gürültüde bu tür bir farkın kaybolmasına neden olur.
Travis Griggs

6
@TravisGriggs kayan noktalı matematik yerine tamsayı matematik kullanmak sadece hız için değildir. Yeterince büyük tamsayılar için float math yanlış cevap veriyor
endolith

1
Eğer foo = -8ve bar = -4, örneğin, cevap 3 değil, 2 olmalıdır -8 // -4. Python taban bölümü, "sonuca uygulanan 'zemin' işlevi ile matematiksel bölme" olarak tanımlanır ve tavan bölme aynı şeydir, ancak ceil()bunun yerine floor().
endolith

8

Math.ceil'in 53 bitlik hassasiyetle sınırlı olduğunu unutmayın. Büyük tam sayılarla çalışıyorsanız, kesin sonuçlar alamayabilirsiniz.

Gmpy2 kitaplığındaki bir sağlar c_divtavan yuvarlama kullanan işlevi.

Sorumluluk reddi: gmpy2'yi koruyorum.


3
Bu paket, matematik veya bilim odaklı bir şey yapıyor olsaydım faydalı olurdu, ancak çekirdek kütüphaneleri kullanan cevabı tercih ederim. Yararlı bir cevap olduğu için bir olumlu oy veriyorum
Cradam

Vay canına, onaylayabilirim. python2 -c 'from math import ceil;assert ceil(11520000000000000102.9)==11520000000000000000'(aynı zamanda ikame de python3)True
JamesTheAwesomeDude

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.