Python'da tamsayı bölme ve float-int dönüşümü arasındaki farkın nedeni nedir?


52

Geçenlerde fark ettim int() bir şamandırayı 0'a yuvarlarken, tamsayı bölümü zemine doğru bir şamandıra yuvarladığını .

Örneğin:

-7 // 2 = -4
int(-7/2) = -3

Belirten belgeleri okudum:

int sınıfı (x; taban = 10)

Bir sayı veya dize x'ten oluşan bir tamsayı nesnesi döndürün veya herhangi bir bağımsız değişken verilmemişse 0 döndürün. X bir sayı ise, x döndür. int (). Kayan nokta sayıları için bu sıfıra doğru kısalır.

ve:

kat bölümü

En yakın tamsayıya yuvarlanan matematik bölümü . Kat bölümü operatörü //. Örneğin, 11 // 4 ifadesi, kayan noktalı gerçek bölümü tarafından döndürülen 2,75'in aksine 2 olarak değerlendirilir. (-11) // 4'ün -3 olduğunu unutmayın, çünkü -2.75 aşağı doğru yuvarlanır. Bkz. PEP 238.

Ancak benim için 2 benzer işlemin (tam sayıya kayan bölüm) farklı sonuçlar döndürmesi mantıksız görünüyor.

Fonksiyonlar arasındaki farklar için herhangi bir motivasyon var mı?

Teşekkür ederim.


Yanıtlar:


61

Tutarlılık.

Bunu anlamak için çok temel ve görünüşte alakasız açıklamaları takip etmeniz gerekir.

Okulda bir kalanla bölünmeyi öğrendiniz. Ve bunun gibi hesaplamalar yaptınız:

8 ÷ 4 = 2 R 0
7 ÷ 4 = 1 R 3
6 ÷ 4 = 1 R 2
5 ÷ 4 = 1 R 1
4 ÷ 4 = 1 R 0
3 ÷ 4 = 0 R 3
2 ÷ 4 = 0 R 2
1 ÷ 4 = 0 R 1
0 ÷ 4 = 0 R 0
        ^------ This is the result of x // 4
            ^-- This is the result of x % 4 (modulo)

Daha sonra, gerçek sayılar için bölümler öğrendiniz:

8 ÷ 4 = 2.0
7 ÷ 4 = 1.75
6 ÷ 4 = 1.5
5 ÷ 4 = 1.25
4 ÷ 4 = 1.0
3 ÷ 4 = 0.75
2 ÷ 4 = 0.5
1 ÷ 4 = 0.25
0 ÷ 4 = 0.0
        ^--- Note that the number in front of the . is int(x/4)

Bu noktaya kadar, x // 4 veint(x/4) her zaman aynı sonucu verebilirsiniz. Bu sizin şu anki durum anlayışınız.

Bununla birlikte, tamsayı bölümünde neler olduğuna bir bakın: R'nin arkasındaki sayı 3, 2, 1'den 0'a döner ve sonra yeniden başlar: 3, 2, 1, 0. R'nin önündeki sayı her 4 adımda bir azalır.

Peki, nasıl olacak?

 8 ÷ 4 =  2 R 0
 7 ÷ 4 =  1 R 3
 6 ÷ 4 =  1 R 2
 5 ÷ 4 =  1 R 1
 4 ÷ 4 =  1 R 0
 3 ÷ 4 =  0 R 3
 2 ÷ 4 =  0 R 2
 1 ÷ 4 =  0 R 1
 0 ÷ 4 =  0 R 0
-1 ÷ 4 = -1 R 3
         ^------ We have to decrease now, because we already have 0 four times
              ^-- We have to restart the cycle at 3

Aynı zamanda, gerçek sayı bölümü bize şunları verir:

-1 ÷ 4 = -0.25
          ^----- There is still a 0 in front of the .

Bu yüzden -1 // 4-1 int(-1/4)verir ancak 0 verir.

Fonksiyonlar arasındaki farklar için herhangi bir motivasyon var mı?

Farklı amaçlara hizmet ediyorlar: //kalanlarla tamsayı hesaplamasının bir parçası ve int()size. gerçek sayı işleminin .

Neyi hesaplamak istediğinize siz karar verirsiniz, ardından doğru sonucu elde etmek için Python'da hangi operatörün kullanılacağına siz karar verirsiniz.

İyi soru. Öğrenmeye devam edin.


11
Pratikte, bu bir hile sağlar: -1 tatlılarınız varsa ve 4 arkadaşınıza verirseniz, 3 tatlı kalır. Harika, değil mi? Sadece -1 tatlıya nasıl sahip olduğunuzu öğrenmeniz gerekir.
Thomas Weller

1
//Int (float) kullanımını zorlamaktan kaçınmak için python 3'te operatör eklemenin motivasyonunu anladığım kadarıyla bir çeşit tutarlılık yaratır . Eğer durum böyle değilse, ne zaman kullanarak uygulamayı seçmeliyim int()ve ne zaman kullanarak uygulamalıyım//
IsaacDj

1
Tamam, o zaman yanlış bir varsayım. Muhtemelen vakaların% 50'sinde başarısız olan varsayımlarınızı doğruluk açısından test ettiğiniz sürece bu kötü bir şey değildir (en azından benim için yapar). Cevaba bununla ilgili bazı kelimeler ekledim.
Thomas Weller

2
@IsaacDj "kat bölümü" operatörünün arkasındaki hikaye için bunu okumak isteyebilirsiniz .
bruno desthuilliers

1
@EricLippert: Bunun tuhaf olduğunu düşünmüyorum. Kayıplı bir işlemin hassas bir işlemle aynı sonucu verdiğini varsayamayız. Kodda konuşulur: Math.Floor(3.23) != -Math.Floor(-3.23)Aynı nedenden dolayı -((-x)//y)eşit olmak zorunda değildir x//y.
Thomas Weller

4

Pozitif sayılarda aynı şekilde davrandıkları için bu 2 operasyonun sezgisel olarak benzer olması gerektiği gözleminizin beklendiğini söyleyebilirim. Ama eğer kökenlerine bakarsanız (biri matematikten diğeri bilgisayar biliminden gelir) farklı davranışları daha mantıklıdır.

Orada kavramlara bakabilirsiniz:

  • Kat bölümü aka matematik bölümüne uygulanan kat işlevi
  • Tip dönüştürme / Tip döküm

================================================== ================

I) Kat bölümü aka matematik bölümüne uygulanan kat işlevi

Zemin fonksiyonu matematikte çok iyi bilinen bir kavramdır.

Gönderen mathworld.wolfram :

En büyük tamsayı işlevi veya tamsayı değeri olarak da adlandırılan zemin işlevi | _ x_ | (Spanier ve Oldham 1987), x değerine eşit veya daha küçük en büyük tamsayıyı verir. Zemin fonksiyonunun adı ve sembolü KE Iverson tarafından yapılmıştır (Graham ve ark. 1994)

Bu nedenle kat bölümü, matematik bölümüne uygulanan kat işlevinden başka bir şey değildir. Davranış çok açık, "matematiksel olarak hassas".

II) Tip dönüştürme / Tip döküm

Gönderen wikipedia :

Bilgisayar biliminde, tür dönüşümü, tür dökümü, tür zorlaması ve tür hokkabazlığı, bir ifadeyi bir veri türünden diğerine değiştirmenin farklı yoludur.

Programlama dillerinin çoğunda, tamsayıya kayan döküm formu yuvarlama kuralı ile uygulanır (bu nedenle bir kural vardır):

  • 0'a yuvarla - sıfıra doğru yönlendirilmiş yuvarlama (kesme olarak da bilinir)

IEEE 754'e göre yuvarlama kuralı .


Yani, başka bir deyişle, python'da tamsayı bölünmesi ve float ile int dönüşümü arasındaki farkın matematiksel bir nedeni, Guido van Rossum'dan bazı düşünceler (sanırım onu ​​tanıtmak zorunda değilim: D) ( blog Python'un tarihi, "Neden Python'un Tamsayı Bölümü Zeminleri" makalesi )

Bu bazı insanları rahatsız ediyor, ancak iyi bir matematiksel sebep var. Tamsayı bölme işlemi (//) ve kardeşi, modulo işlemi (%), birlikte gider ve hoş bir matematiksel ilişkiyi tatmin eder (tüm değişkenler tamsayıdır):

a / b = q, kalan r ile

öyle ki

b * q + r = a ve 0 <= r <b

(a ve b'nin = = 0 olduğu varsayılarak).

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.