การแบ่ง Python


134

ฉันพยายามทำให้ชุดตัวเลขเป็นปกติจาก -100 ถึง 0 เป็นช่วง 10-100 และมีปัญหาเพียงเพื่อสังเกตว่าแม้จะไม่มีตัวแปรเลย แต่ก็ไม่ได้ประเมินวิธีที่ฉันคาดหวังไว้:

>>> (20-10) / (100-10)
0

การแบ่งลอยไม่ทำงาน:

>>> float((20-10) / (100-10))
0.0

หากด้านใดด้านหนึ่งของการหารถูกเหวี่ยงให้ลอยมันจะทำงาน:

>>> (20-10) / float((100-10))
0.1111111111111111

แต่ละด้านในตัวอย่างแรกกำลังประเมินเป็น int ซึ่งหมายความว่าคำตอบสุดท้ายจะถูกส่งไปยัง int เนื่องจาก 0.111 น้อยกว่า. 5 จึงปัดเศษเป็น 0 ในความคิดของฉันไม่โปร่งใส แต่ฉันเดาว่าเป็นอย่างนั้น

มีคำอธิบายอย่างไร?



3
อดัมฉันยังไม่ชอบคำอธิบายของคุณ ตัวอย่างแรกคือการหารจำนวนเต็มซึ่งจะคืนค่า 0 ตัวอย่างที่สองวงเล็บผิดสำหรับเอฟเฟกต์ที่คุณต้องการ
ประธาน James K. Polk

@GregS ตัวอย่างแรกคือปัญหา ตัวอย่างที่สองอธิบายได้และเขียนไว้หลังคำถามแรก คำตอบทั้งหมดด้านล่างอธิบายปัญหาได้เป็นอย่างดีโดยเฉพาะ @Kenny ™ สิ่งสำคัญคือต้องทราบว่าปัญหาเดิมของฉันเป็นเพียงปัญหาใน Python 2.x ไม่ใช่ 3 เป็นเรื่องที่น่ากังวลเล็กน้อยที่พฤติกรรมจะเปลี่ยนไปเช่นนั้น แต่ตอนนี้ฉันรู้แล้วฉันจะใช้จากแผนกนำเข้าในอนาคตและใช้ 3 .x พฤติกรรม ไชโย
Adam Nelson

1
อดัมโปรดแก้ไขการแก้ไขล่าสุดของคุณ ด้านขวาไม่มีอะไรพิเศษ เพื่อให้การหารลอยได้ทั้งตัวเศษหรือตัวส่วน (หรือทั้งสองอย่าง) จะต้องลอย หากคุณคิดว่าคุณอ่านเอกสารแล้วว่าทางด้านขวามือจำเป็นต้องลอยแสดงว่าเอกสารนั้นมีวลีที่ไม่ถูกต้องและควรได้รับการแก้ไขหรือคุณเข้าใจผิด คุณเห็นตัวอย่างหรือไม่และอาจคาดคะเนกฎออกมาได้หรือไม่?
tzot

คำตอบ:


246

คุณกำลังใช้ Python 2.x ซึ่งการหารจำนวนเต็มจะตัดทอนแทนที่จะกลายเป็นตัวเลขทศนิยม

>>> 1 / 2
0

คุณควรทำให้หนึ่งในนั้นเป็นfloat:

>>> float(10 - 20) / (100 - 10)
-0.1111111111111111

หรือfrom __future__ import divisionซึ่งบังคับ/ให้นำพฤติกรรมของ Python 3.x ที่ส่งกลับค่าลอยเสมอ

>>> from __future__ import division
>>> (10 - 20) / (100 - 10)
-0.1111111111111111

10
หากคุณใช้from __future__ import divisionคุณจะได้รับพฤติกรรมการหารสไตล์ C แบบเก่าโดยใช้เครื่องหมายทับสองตัว (เช่น1 // 2จะให้ผลลัพธ์เป็น 0) ดูPep 238 การเปลี่ยน Division Operator
ผู้ใช้

1
@ ผู้ใช้ไม่จำเป็นต้องนำเข้าจาก__future__. ใน Python 2 และ 3 //อ้างถึง__floordiv__()โดยค่าเริ่มต้น
Casimir

21

คุณกำลังใส่จำนวนเต็มดังนั้น Python จึงให้จำนวนเต็มกลับมา :

>>> 10 / 90
0

ถ้าหากคุณโยนสิ่งนี้เป็นลูกลอยหลังจากนั้นการปัดเศษจะถูกทำไปแล้วกล่าวคือจำนวนเต็ม 0 จะกลายเป็น 0 ลอยเสมอ

หากคุณใช้ float ที่ด้านใดด้านหนึ่งของการหาร Python จะให้คำตอบที่คุณคาดหวัง

>>> 10 / 90.0
0.1111111111111111

ดังนั้นในกรณีของคุณ:

>>> float(20-10) / (100-10)
0.1111111111111111
>>> (20-10) / float(100-10)
0.1111111111111111

11

คุณต้องเปลี่ยนเป็นลอยก่อนที่คุณจะทำการหาร นั่นคือ:

float(20 - 10) / (100 - 10)

4
@Adam Nelson: ทำงานได้ถูกต้องสำหรับฉัน ตรวจสอบวงเล็บของคุณ
Fred Larson

อันที่จริงฉันผิด - แต่หลังจากดูเอกสารแล้วควรโยนด้านขวาก่อน
Adam Nelson

10
@Adam: ไม่สำคัญว่าฝ่ายไหนก่อน
kennytm

11

ใน Python 2.7 ตัว/ดำเนินการคือการหารจำนวนเต็มหากอินพุตเป็นจำนวนเต็ม:

>>>20/15
1

>>>20.0/15.0
1.33333333333

>>>20.0/15
1.33333333333

ใน Python 3.3 ตัว/ดำเนินการคือการหารแบบโฟลทแม้ว่าอินพุตจะเป็นจำนวนเต็มก็ตาม

>>> 20/15
1.33333333333

>>>20.0/15
1.33333333333

สำหรับการหารจำนวนเต็มใน Python 3 เราจะใช้ตัว//ดำเนินการ

ตัว//ดำเนินการเป็นตัวดำเนินการหารจำนวนเต็มทั้งใน Python 2.7 และ Python 3.3

ใน Python 2.7 และ Python 3.3:

>>>20//15
1

ตอนนี้ดูการเปรียบเทียบ

>>>a = 7.0/4.0
>>>b = 7/4
>>>print a == b

สำหรับโปรแกรมข้างต้นผลลัพธ์จะเป็น False ใน Python 2.7 และ True ใน Python 3.3

ใน Python 2.7 a = 1.75 และ b = 1

ใน Python 3.3 a = 1.75 และ b = 1.75 เพียงเพราะ/เป็นการหารแบบลอย


8

มันเกี่ยวข้องกับเวอร์ชันของ python ที่คุณใช้ โดยทั่วไปจะใช้พฤติกรรม C: ถ้าคุณหารจำนวนเต็มสองจำนวนผลลัพธ์จะถูกปัดเศษเป็นจำนวนเต็ม โปรดทราบว่า Python ดำเนินการจากซ้ายไปขวาซึ่งมีบทบาทเมื่อคุณพิมพ์แคสต์

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

>>> a = 1/2/3/4/5/4/3
>>> a
0

เมื่อเราหารจำนวนเต็มไม่น่าแปลกใจที่มันจะปัดเศษต่ำลง

>>> a = 1/2/3/4/5/4/float(3)
>>> a
0.0

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

>>> a = 1/2/3/float(4)/5/4/3
>>> a
0.0

สถานการณ์เดียวกันกับด้านบน แต่เลื่อนตัวพิมพ์ลอยไปทางด้านซ้ายเล็กน้อย

>>> a = float(1)/2/3/4/5/4/3
>>> a
0.0006944444444444445

สุดท้ายเมื่อเราพิมพ์จำนวนเต็มแรกที่จะลอยผลลัพธ์ก็คือค่าที่ต้องการเนื่องจากเริ่มต้นจากการหารแรกนั่นคือค่าทางซ้ายสุดเราใช้การลอย

พิเศษ 1: หากคุณกำลังพยายามตอบคำถามเพื่อปรับปรุงการประเมินผลทางคณิตศาสตร์คุณควรตรวจสอบสิ่งนี้

พิเศษ 2: โปรดระวังสถานการณ์ต่อไปนี้:

>>> a = float(1/2/3/4/5/4/3)
>>> a
0.0


2

ทำให้อย่างน้อยหนึ่งลอยจากนั้นจะเป็นส่วนลอยไม่ใช่จำนวนเต็ม:

>>> (20.0-10) / (100-10)
0.1111111111111111

การหล่อผลลัพธ์ให้ลอยนั้นสายเกินไป


1

ใน python cv2ไม่ได้อัปเดตการคำนวณหาร ดังนั้นคุณต้องรวมfrom __future__ import division ไว้ในบรรทัดแรกของโปรแกรม


0

ไม่ว่าจะด้วยวิธีใดก็คือการหารจำนวนเต็ม 10/90 = 0 ในกรณีที่สองคุณกำลังร่าย 0 เป็นลูกลอย

ลองแคสต์หนึ่งในตัวถูกดำเนินการของ "/" ให้เป็นโฟลต:

float(20-10) / (100-10)

0

คุณกำลังแคสต์ให้ลอยหลังจากการหารเกิดขึ้นแล้วในตัวอย่างที่สองของคุณ ลองสิ่งนี้:

float(20-10) / float(100-10)

0

ผมค่อนข้างแปลกใจที่ไม่มีใครได้บอกว่าโปสเตอร์เดิมอาจจะชอบที่มีเหตุผลตัวเลขผล หากคุณสนใจสิ่งนี้โปรแกรมที่ใช้ Python Sage จะช่วยคุณได้ (ปัจจุบันยังคงใช้ Python 2.x แม้ว่า 3.x อยู่ระหว่างดำเนินการ)

sage: (20-10) / (100-10)
1/9

นี่ไม่ใช่วิธีแก้ปัญหาสำหรับทุกคนเพราะมีการเตรียมการบางอย่างดังนั้นตัวเลขเหล่านี้จึงไม่ใช่ints แต่เป็นIntegerองค์ประกอบระดับSage ถึงกระนั้นก็ควรค่าแก่การกล่าวขวัญว่าเป็นส่วนหนึ่งของระบบนิเวศ Python


0

โดยส่วนตัวแล้วฉันชอบที่จะแทรก1. *ที่จุดเริ่มต้นมาก ดังนั้นการแสดงออกจึงกลายเป็นดังนี้:

1. * (20-10) / (100-10)

อย่างที่ฉันทำหารสำหรับสูตรบางอย่างเช่น:

accuracy = 1. * (len(y_val) - sum(y_val)) / len(y_val)

ดังนั้นจึงเป็นไปไม่ได้ที่จะเพียงแค่เพิ่มเช่น.0 20.0และในกรณีของฉันการห่อด้วย a float()อาจสูญเสียความสามารถในการอ่านไปเล็กน้อย

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