อะไรคือสาเหตุของความแตกต่างระหว่างการหารจำนวนเต็มและการแปลงทศนิยมเป็นการแปลง int ในไพ ธ อน?


52

ฉันเพิ่งสังเกตเห็นว่าการint()ปัดเศษเป็นทศนิยมให้เป็น 0 ในขณะที่การแบ่งจำนวนเต็มปัดลอยไปทางพื้น

เช่น:

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

ฉันได้อ่านเอกสารที่ระบุว่า:

คลาส int (x, ฐาน = 10)

ส่งคืนวัตถุจำนวนเต็มที่สร้างจากตัวเลขหรือสตริง x หรือส่งคืน 0 หากไม่มีการระบุอาร์กิวเมนต์ ถ้า x เป็นตัวเลขให้ส่งคืน x int () สำหรับจำนวนจุดลอยตัวสิ่งนี้จะตัดให้เหลือศูนย์

และ:

การแบ่งชั้น

ส่วนคณิตศาสตร์ที่ปัดเศษลงเป็นจำนวนเต็มที่ใกล้เคียงที่สุด ตัวดำเนินการหารพื้นคือ // ตัวอย่างเช่นนิพจน์ 11 // 4 ประเมินเป็น 2 ตรงกันข้ามกับ 2.75 ที่ส่งกลับโดยการหารทรูที่แท้จริง โปรดทราบว่า (-11) // 4 คือ -3 เพราะนั่นคือ -2.75 ปัดเศษลง ดู PEP 238

แต่ดูเหมือนไม่มีเหตุผลสำหรับฉันว่าการดำเนินการ 2 อย่างที่คล้ายกัน (การหารทศนิยมเป็นจำนวนเต็ม) ควรให้ผลลัพธ์ที่แตกต่างกัน

มีแรงจูงใจสำหรับความแตกต่างระหว่างฟังก์ชั่นหรือไม่?

ขอบคุณ.


ลิงค์ที่เกี่ยวข้อง: python-history.blogspot.com/2010/08/…
dan04

คำตอบ:


61

ความมั่นคง

คุณจะต้องทำตามคำอธิบายพื้นฐานและไม่เกี่ยวข้องดูเหมือนจะเข้าใจ

ในโรงเรียนคุณได้เรียนรู้การแบ่งส่วนที่เหลือ และคุณทำการคำนวณแบบนี้:

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)

ต่อมาคุณได้เรียนรู้การหารสำหรับจำนวนจริง:

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)

จนถึงจุดนี้คุณอาจเชื่อx // 4และint(x/4)ให้ผลเหมือนเดิมเสมอ นั่นคือความเข้าใจในสถานการณ์ปัจจุบันของคุณ

อย่างไรก็ตามดูสิ่งที่เกิดขึ้นในการแบ่งจำนวนเต็ม: จำนวนที่อยู่เบื้องหลังรอบ R จาก 3, 2, 1 ถึง 0 แล้วเริ่มต้นใหม่: 3, 2, 1, 0 จำนวนหน้า R จะลดลงทุกขั้นตอนที่ 4

แล้วมันจะดำเนินต่อไปอย่างไร

 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

ในเวลาเดียวกันการแบ่งจำนวนจริงให้เรา:

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

นั่นคือเหตุผลที่-1 // 4ให้ -1 แต่int(-1/4)ให้ 0

มีแรงจูงใจสำหรับความแตกต่างระหว่างฟังก์ชั่นหรือไม่?

มันให้บริการตามวัตถุประสงค์ที่แตกต่างกัน: //เป็นส่วนหนึ่งของการคำนวณจำนวนเต็มพร้อมเศษและint()ให้ส่วนหน้าของการ.ดำเนินการจำนวนจริง

คุณตัดสินใจว่าคุณต้องการคำนวณอะไรจากนั้นคุณตัดสินใจว่าผู้ให้บริการรายใดที่จะใช้ใน Python เพื่อให้ได้ผลลัพธ์ที่ถูกต้อง

คำถามที่ดี. เรียนรู้ต่อไป


11
ในทางปฏิบัติสิ่งนี้อนุญาตให้ใช้เคล็ดลับ: หากคุณมี -1 สวีทและคุณแจกให้เพื่อน 4 คนจะมีเหลืออีก 3 เม็ด เยี่ยมเลยใช่ไหม คุณต้องค้นหาวิธีการเป็นเจ้าของ -1 ขนมหวาน
โทมัสเวลเลอร์

1
มันสร้างความสอดคล้องบางอย่าง แต่เท่าที่ฉันเข้าใจแรงจูงใจในการเพิ่ม//ผู้ประกอบการในหลาม 3 คือเพื่อหลีกเลี่ยงการบังคับใช้ int (ลอย) หากไม่เป็นเช่นนั้นฉันควรเลือกใช้int()เมื่อไรและควรใช้//
เมื่อไร

1
ตกลงแล้วมันเป็นเพียงสมมติฐานที่ผิด นั่นคือไม่มีอะไรเลวร้ายตราบใดที่คุณทดสอบสมมติฐานของคุณสำหรับความถูกต้องซึ่งอาจล้มเหลวใน 50% ของกรณี (อย่างน้อยก็สำหรับฉัน) ฉันเพิ่มบางคำเข้าไปในคำตอบ
โทมัสเวลเลอร์

2
@IsaacDj คุณอาจต้องการอ่านเรื่องนี้เบื้องหลังผู้ดำเนินการ "การแบ่งชั้น"
bruno desthuilliers

1
@EricLippert: ฉันไม่คิดว่ามันแปลกประหลาด เราไม่สามารถสรุปได้ว่าการดำเนินการสูญเสียนั้นให้ผลลัพธ์เช่นเดียวกับการดำเนินการที่แม่นยำ พูดในรหัส: Math.Floor(3.23) != -Math.Floor(-3.23)ด้วยเหตุผลเดียวกันไม่จำเป็นต้องเท่ากัน-((-x)//y) x//y
โทมัสเวลเลอร์

4

ฉันจะบอกว่าการสังเกตของคุณว่าการดำเนินการทั้งสองนั้นควรจะคล้ายกันอย่างสังหรณ์ใจเนื่องจากคาดว่าจะมีจำนวนบวกที่พวกเขาทำงานเหมือนกัน แต่ถ้าคุณดูที่ต้นกำเนิดของพวกเขา (อันหนึ่งมาจากคณิตศาสตร์และอีกอันจากวิทยาการคอมพิวเตอร์) มันก็จะทำให้คุณรู้สึกถึงพฤติกรรมที่แตกต่างกัน

คุณสามารถดูแนวคิดเบื้องหลัง:

  • การหารชั้น aka ฟังก์ชันพื้นนำไปใช้กับการหารทางคณิตศาสตร์
  • แปลงประเภท / หล่อประเภท

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

I) ส่วนของพื้นหรือที่รู้จักกันว่าฟังก์ชันพื้นใช้กับแผนกคณิตศาสตร์

ฟังก์ชั่นชั้นเป็นแนวคิดที่จัดตั้งขึ้นเป็นอย่างดีในวิชาคณิตศาสตร์

จากmathworld.wolfram :

ฟังก์ชันพื้น | _ x_ | หรือที่เรียกว่าฟังก์ชันจำนวนเต็มมากที่สุดหรือค่าจำนวนเต็ม (Spanier และ Oldham 1987) ให้จำนวนเต็มที่มากที่สุดน้อยกว่าหรือเท่ากับ x ชื่อและสัญลักษณ์ของฟังก์ชันพื้นประกาศเกียรติคุณโดย KE Iverson (Graham et al. 1994)

ดังนั้นการแบ่งพื้นไม่มีอะไรมากไปกว่าฟังก์ชั่นพื้นที่ใช้กับการหารคณิตศาสตร์ พฤติกรรมมีความชัดเจนมาก "แม่นยำทางคณิตศาสตร์"

II) การแปลงแบบ / การหล่อแบบ

จากวิกิพีเดีย :

ในวิทยาการคอมพิวเตอร์, การแปลงชนิด, การพิมพ์ชนิด, การบังคับประเภทและการเล่นกลประเภทเป็นวิธีที่แตกต่างกันในการเปลี่ยนนิพจน์จากประเภทข้อมูลหนึ่งไปเป็นอีกประเภทหนึ่ง

ในภาษาการเขียนโปรแกรมส่วนใหญ่รูปแบบการหล่อลอยไปเป็นจำนวนเต็มถูกใช้โดยกฎการปัดเศษ (ดังนั้นจึงมีการประชุม):

  • ปัดเศษเป็น 0 - สั่งการปัดเศษเป็นศูนย์ (เรียกอีกอย่างว่าการตัดปลาย)

ปัดเศษกฎตามมาตรฐาน IEEE 754


ดังนั้นในคำอื่น ๆ เหตุผลสำหรับความแตกต่างระหว่างการหารจำนวนเต็มและการแปลงทศนิยมเป็นการแปลง int ในไพ ธ อนเป็นคณิตศาสตร์นี่เป็นความคิดจาก Guido van Rossum (ฉันเดาว่าฉันไม่ต้องแนะนำเขา: D) (จาก บล็อกประวัติของ Python บทความ"Why Python Integer Division Floors" )

สิ่งนี้รบกวนบางคน แต่มีเหตุผลทางคณิตศาสตร์ที่ดี การดำเนินการหารจำนวนเต็ม (//) และพี่น้อง, การดำเนินการ modulo (%), ไปด้วยกันและตอบสนองความสัมพันธ์ทางคณิตศาสตร์ที่ดี (ตัวแปรทั้งหมดเป็นจำนวนเต็ม):

a / b = q พร้อมเศษเหลือ r

ดังนั้น

b * q + r = a และ 0 <= r <b

(สมมติว่า a และ b เป็น> = 0)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.