เหตุใดการดำเนินการทางคณิตศาสตร์ของ Python math.ceil () และ math.floor () จึงกลับลอยแทนจำนวนเต็ม?


170

ใครสามารถอธิบายสิ่งนี้ (ตรงจากเอกสาร - เน้นการทำเหมือง):

math.ceil (x)คืนค่าเพดานของ x เป็นทศนิยมค่าจำนวนเต็มเล็กที่สุดที่มากกว่าหรือเท่ากับ x

math.floor (x)คืนค่าพื้นของ x เป็นทศนิยมค่าจำนวนเต็มที่มากที่สุดน้อยกว่าหรือเท่ากับ x

ทำไม.ceilและจะ.floorคืนค่าลอยเมื่อนิยามตามคำจำกัดความเพื่อคำนวณจำนวนเต็ม?


แก้ไข:

อย่างนี้มีข้อโต้แย้งที่ดีบางอย่างว่าทำไมพวกเขาควรจะกลับลอยและฉันก็เพิ่งเริ่มใช้ความคิดเมื่อ@jcolladoชี้ให้เห็นว่าพวกเขาในความเป็นจริงทำ ints ผลตอบแทนในหลาม 3 ...


1
ฉันเดาว่าจะเป็นเพราะ x เป็นทศนิยมไม่ใช่จำนวนเต็ม แต่เนื่องจากฉันไม่รู้จักหรือใช้ Python ฉันจะให้คนอื่นตอบอย่างชัดเจนยิ่งขึ้น :)
อดัม V

6
@ Adam- แต่จุดรวมของการทำงานบนเพดาน / พื้นคือการปัดเศษเป็นจำนวนเต็ม!
Yarin

1
นี่เป็นสิ่งที่ทำให้ฉันรำคาญเป็นครั้งแรกที่ฉันเจอมันเพราะมันดูเหมือนผิด int(floor(n))อย่างน้อยก็ไม่ยากเกินไปที่จะใช้
Wim

1
กระแทกแดกดัน (ในขณะที่ลอยถูกนำมาใช้เพื่อป้องกันการล้น), ค่าที่ส่งกลับโดยพื้น / เพดานมีความหมายในหลักต่ำเพราะการเป็นตัวแทนลอยก่อนที่ 64 บิต int จะล้น [สิ่งนี้ไม่เป็นความจริงในสมัย ​​32 บิต]
Yves Daoust

คำตอบ:


99

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

ลองพิจารณา: ถ้าfloor()คืนค่าจำนวนเต็มแล้วจะfloor(1.0e30)คืนอะไร?

ตอนนี้แม้ว่าจำนวนเต็มของ Python จะมีความแม่นยำตามอำเภอใจ แต่ก็ไม่ได้เป็นเช่นนี้เสมอไป ฟังก์ชั่นห้องสมุดมาตรฐานเป็นเครื่องห่อเล็ก ๆ รอบ ๆ ฟังก์ชั่นไลบรารี C ที่เทียบเท่ากัน


13
และแม้ว่าจำนวนเต็มของ Python จะมีความแม่นยำตามอำเภอใจ แต่ก็ยังมีการลอยตัวที่จำนวนเต็มของพื้นและเพดานไม่สามารถแสดงได้ ลองหรือfloor(float("inf")) ceil(float("nan"))
Michael Hoffman

4
@ Michael- เห็นได้ชัดใน P3 คุณจะได้รับ OverflowExceptions ถ้าคุณลองทำดู ดูjcollado 's คำตอบ
Yarin

4
เอ่อมันควรจะกลับมาเป็นแบบ 'ยาว' (aka 'bigint') ใช่ไหม? ดูเหมือนคำตอบที่ชัดเจนสำหรับฉัน แต่ตอนนี้ฉันรู้สึกว่าฉันไร้เดียงสาอย่างใด
koschei

3
@koschei: มันทำใน Python 3.x ดูคำตอบของ jcollado
Greg Hewgill

ดูความคิดเห็นต่อคำตอบอื่น ๆว่าทำไมถึงสมเหตุสมผลสำหรับตัวเลขที่อยู่ในช่วง
ivan_pozdeev

96

ตามที่ระบุไว้โดยคำตอบอื่น ๆ ในหลามพวกเขากลับลอยอาจเป็นเพราะเหตุผลทางประวัติศาสตร์เพื่อป้องกันปัญหาล้น อย่างไรก็ตามพวกเขากลับจำนวนเต็มในหลาม 3

>>> import math
>>> type(math.floor(3.1))
<class 'int'>
>>> type(math.ceil(3.1))
<class 'int'>

คุณสามารถหาข้อมูลเพิ่มเติมได้ในPEP 3141


@ jcollado- คุณเห็นว่าพวกเขากลับจำนวนเต็มใน P3 ที่ไหน
Yarin

4
@Yarin ฉันแค่พิมพ์คำสั่งด้านบน นอกจากนี้หากคุณลองfloat("inf")หรือfloat("nan")คุณจะได้รับการOverflowErrorยกเว้น
jcollado

10
เพื่อความสมบูรณ์ Python numpy.floorและceilreturn float (<class 'numpy.float64'>)
Neil G

1
@jcollado: float("inf")ไม่สร้างข้อยกเว้นใน Python 2.7 หรือ 3
endolith

1
@endolith ถูกต้องฉันตรวจสอบแล้วและมันจะไม่เกิดขึ้นอีก น่าจะเป็นว่าสิ่งที่ได้รับการเปลี่ยนแปลงตั้งแต่ธันวาคม 2011
jcollado

18

แหล่งที่มาของความสับสนของคุณชัดเจนในความคิดเห็นของคุณ:

จุดทั้งหมดของการดำเนินการบนเพดาน / พื้นคือการแปลงเป็นจำนวนเต็ม!

จุด ceil และพื้นการดำเนินงานคือการข้อมูลจุดลอยตัวรอบค่าหนึ่ง ไม่ต้องทำการแปลงประเภท ผู้ใช้ที่ต้องการรับค่าจำนวนเต็มสามารถทำการแปลงที่ชัดเจนหลังจากการดำเนินการ

โปรดทราบว่ามันเป็นไปไม่ได้ที่จะใช้การปัดเศษเป็นค่าอินทิกรัลเป็นเรื่องเล็กน้อยหากสิ่งที่คุณมีอยู่คือการดำเนินการ ceil หรือ float ที่คืนค่าจำนวนเต็ม คุณจะต้องตรวจสอบก่อนว่าอินพุตอยู่ภายในช่วงจำนวนเต็มที่แทนค่าได้จากนั้นเรียกใช้ฟังก์ชัน คุณจะต้องจัดการกับ NaN และอินฟินิตี้ในเส้นทางของรหัสที่แยกต่างหาก

นอกจากนี้คุณต้องมีรุ่นของ ceil และพื้นซึ่งกลับจำนวนจุดลอยตัวถ้าคุณต้องการเพื่อให้สอดคล้องกับมาตรฐาน IEEE 754


สตีเฟ่น - ฉันเขียนความคิดเห็นของฉันใหม่ - ฉันมีความหมายว่าเป็นกลมไม่ใช่เปลี่ยนใจ แต่นั่นไม่ได้เป็นแหล่งที่มาของความสับสนของฉัน - แต่เป็นที่ฉันไม่ได้ตระหนักถึงช่วงที่แตกต่างกัน
Yarin

น่าเศร้าที่ฉันออกจากการลงคะแนนวันนี้ นี่คือคำตอบที่ถูกต้องมากเกินกว่าข้อ จำกัด ใด ๆ ของการเป็นตัวแทน
Marcin

13
ในการเขียนโปรแกรมเป็นเวลาหลายปีฉันจำไม่ได้ว่าเคยเจอสถานการณ์ที่ฉันต้องการผลลัพธ์ของการปูพื้น / เพดานให้เป็นแบบลอยแทนที่จะเป็นจำนวนเต็ม ความจริงที่ว่า python3 ไม่กลับมาแสดงให้เห็นว่าเลขนี้ในความเป็นจริงสิ่งที่มีประโยชน์อื่น ๆ อีกมากมายที่จะทำ ฉันไม่ได้ซื้อการอ้างสิทธิ์ "the point of ... "; ดูเหมือนว่าคุณกำลังกำหนดประเด็นตามสิ่งที่มันทำแทนที่จะเป็นโปรแกรมเมอร์ที่ต้องการ
ShreevatsaR

2
@ShreevatsaR ฉันมีสถานการณ์นั้นสองครั้ง (แต่ส่วนใหญ่อยู่นอกบริบท Python) เวลาที่ฉันจำได้คือเมื่อทำงานกับชุด Mandelbrot บางครั้งคุณจำเป็นต้องสร้างค่าอินทิกรัล แต่จากนั้นให้ใช้การดำเนินการจุดลอยตัวกับค่าทันทีหลังจากนั้น (กล่าวคือปรับขนาดด้วย 0.5) จากนั้นมันจะมีประสิทธิภาพมากขึ้นในการรักษาพื้นลอยและใช้การดำเนินการจุดลอยตัวกับมันมากกว่าการแปลงมันเป็น int ก่อนแล้วจึงแปลงกลับเป็นลอยตัวทันที
blubberdiblub

17

เพราะไลบรารี่คณิตศาสตร์ของไพ ธ อนนั้นเป็นเสื้อคลุมบาง ๆ รอบ ๆ ไลบรารี่คณิตศาสตร์ C ที่คืนค่าลอยตัว


ไลบรารีคณิตศาสตร์ C สนับสนุนจำนวนเต็มความแม่นยำโดยอำเภอใจใช่ไหม เพราะนั่นคือสิ่งที่ฟังก์ชั่นทางคณิตศาสตร์อื่น ๆ กลับมา
endolith

5

ก่อน Python 2.4 จำนวนเต็มไม่สามารถเก็บช่วงจริงของจำนวนที่ถูกตัดทอนได้

http://docs.python.org/whatsnew/2.4.html#pep-237-unifying-long-integers-and-integers


2
ตอนนี้มันไม่สามารถเก็บ "จำนวนจริงที่ถูกตัดทอน" ได้เนื่องจากนั่นเป็นเซตที่ไม่มีที่สิ้นสุดและดังนั้นจึงต้องการหน่วยความจำจำนวนนับไม่ถ้วน มันสามารถเก็บช่วงของการถูกตัดทอนลอยซึ่งเป็น แต่ส่วนย่อยเล็ก ๆ ของℝ
leftaroundabout

6
@leftaroundabout - picky picky! คุณรู้ว่าฉันหมายถึงอะไร
Mark Ransom

4

เนื่องจากช่วงของการลอยตัวมีค่ามากกว่าจำนวนเต็ม - การคืนค่าจำนวนเต็มอาจทำให้เกิดการล้น


7
จำนวนเต็มไม่ล้นใน Python; จำนวนเต็มของมันเปลี่ยนเป็น bigints เมื่อมันใหญ่เกินไป เปิดล่าม Python และพิมพ์ "2 ** 500" แล้วคุณจะเห็นว่าคุณได้รับวัตถุที่คุณสามารถปฏิบัติได้ทุกอย่างเหมือน int
koschei

@koschei: แม้กระแสใหญ่เกินควรเมื่อพยายามเป็นตัวแทนของอินฟินิตี้
Stephen Canon

4

นี่เป็นคำถามที่น่าสนใจมาก! เนื่องจากการลอยตัวต้องใช้บิตบางส่วนในการเก็บเลขชี้กำลัง (= bits_for_exponent) จำนวนจุดลอยตัวใด ๆ ที่มากกว่า2**(float_size - bits_for_exponent)นั้นจะเป็นค่าสำคัญ! ที่มาก ๆ ลอยกับตัวแทนเชิงลบจะให้หนึ่ง1, หรือ0 -1สิ่งนี้ทำให้การอภิปรายของช่วงจำนวนเต็มเมื่อเทียบกับช่วง moot เพราะฟังก์ชั่นเหล่านี้จะกลับจำนวนเดิมเมื่อใดก็ตามที่ตัวเลขอยู่นอกช่วงของประเภทจำนวนเต็ม ฟังก์ชั่นของไพ ธ อนนั้นเป็นส่วนเสริมของCฟังก์ชั่นดังนั้นนี่จึงเป็นข้อบกพร่องของCฟังก์ชั่นที่พวกมันควรจะคืนค่าจำนวนเต็มและบังคับให้ผู้เขียนโปรแกรมทำช่วง / NaN/ Infเช็คก่อนที่จะเรียก ceil / floor

ดังนั้นคำตอบเชิงตรรกะเป็นเพียงครั้งเดียวที่ฟังก์ชั่นเหล่านี้มีประโยชน์พวกเขาจะคืนค่าภายในช่วงจำนวนเต็มดังนั้นความจริงที่ว่าพวกเขาคืนค่าทศนิยมเป็นความผิดพลาดและคุณฉลาดมากสำหรับการตระหนักถึงสิ่งนี้!


1

อาจเป็นเพราะภาษาอื่นทำได้เช่นกันดังนั้นจึงเป็นพฤติกรรมที่ยอมรับกันโดยทั่วไป (สำหรับเหตุผลที่ดีดังแสดงในคำตอบอื่น ๆ )


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