ฉันพบพฤติกรรมแปลก ๆ ใน Python เกี่ยวกับจำนวนลบ:
>>> -5 % 4
3
ใครช่วยอธิบายว่าเกิดอะไรขึ้น
ฉันพบพฤติกรรมแปลก ๆ ใน Python เกี่ยวกับจำนวนลบ:
>>> -5 % 4
3
ใครช่วยอธิบายว่าเกิดอะไรขึ้น
..., -9, -5, -1, 3, 7, ...
math.fmod
เพื่อให้ได้พฤติกรรมเช่นเดียวกับใน C หรือ Java
คำตอบ:
ต่างจาก C หรือ C ++ ตัวดำเนินการโมดูโลของ Python ( %
) จะส่งคืนตัวเลขที่มีเครื่องหมายเดียวกับตัวหาร (ตัวหาร) เสมอ นิพจน์ของคุณให้ 3 เนื่องจาก
(-5) / 4 = -1.25 -> ชั้น (-1.25) = -2
(-5)% 4 = (-2 × 4 + 3)% 4 = 3
ถูกเลือกมากกว่าพฤติกรรม C เนื่องจากผลลัพธ์ที่ไม่เป็นค่าลบมักจะมีประโยชน์มากกว่า ตัวอย่างคือการคำนวณวันในสัปดาห์ ถ้าวันนี้เป็นวันอังคาร (วัน # 2) วันในสัปดาห์Nวันก่อนหน้าคืออะไร? ใน Python เราสามารถคำนวณด้วย
return (2 - N) % 7
แต่ใน C ถ้าN ≥ 3 เราจะได้จำนวนลบซึ่งเป็นตัวเลขที่ไม่ถูกต้องและเราจำเป็นต้องแก้ไขด้วยตนเองโดยการเพิ่ม 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(ดูhttp://en.wikipedia.org/wiki/Modulo_operatorสำหรับวิธีกำหนดเครื่องหมายของผลลัพธ์สำหรับภาษาต่างๆ)
นี่คือคำอธิบายจาก Guido van Rossum:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
โดยพื้นฐานแล้ว a / b = q พร้อมส่วนที่เหลือ r รักษาความสัมพันธ์ b * q + r = a และ 0 <= r <b
a
บวกb
ในขณะที่พื้น Python มันเสมอความจริงที่ว่าabs(r) < b
และพวกเขา ceil r <= 0
IFF
ไม่มีวิธีใดวิธีหนึ่งที่ดีที่สุดในการจัดการการหารจำนวนเต็มและม็อดด้วยจำนวนลบ คงจะดีถ้าa/b
มีขนาดเดียวกันและมีเครื่องหมายตรงข้าม(-a)/b
กัน คงจะดีไม่น้อยถ้าa % b
เป็นโมดูโล b เนื่องจากเราต้องการจริงๆa == (a/b)*b + a%b
สองข้อแรกจึงเข้ากันไม่ได้
คำถามที่ตอบยากและมีข้อโต้แย้งสำหรับทั้งสองฝ่าย การหารจำนวนเต็มรอบ C และ C ++ ต่อศูนย์ (ดังนั้นa/b == -((-a)/b)
) และดูเหมือนว่า Python จะไม่
ดังที่ได้กล่าวไปแล้ว Python modulo ให้ข้อยกเว้นที่สมเหตุสมผลสำหรับอนุสัญญาของภาษาอื่น ๆ
สิ่งนี้ทำให้ตัวเลขเชิงลบเป็นพฤติกรรมที่ราบรื่นโดยเฉพาะอย่างยิ่งเมื่อใช้ร่วมกับ//
ตัวดำเนินการหารจำนวนเต็มเนื่องจาก%
โมดูโลมักจะเป็น (เช่นเดียวกับในคณิตศาสตร์divmod ):
for n in range(-8,8):
print n, n//4, n%4
ผลิต:
-8 -2 0
-7 -2 1
-6 -2 2
-5 -2 3
-4 -1 0
-3 -1 1
-2 -1 2
-1 -1 3
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3
%
ผลลัพธ์เป็นศูนย์หรือบวกเสมอ *//
จะปัดเศษเข้าหาอินฟินิตี้เชิงลบเสมอ* ... ตราบใดที่ตัวถูกดำเนินการด้านขวาเป็นค่าบวก ในทางกลับกัน11 % -10 == -9
ในpythonตัวดำเนินการโมดูโลจะทำงานเช่นนี้
>>> mod = n - math.floor(n/base) * base
ดังนั้นผลลัพธ์คือ (สำหรับกรณีของคุณ):
mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
ในขณะที่ภาษาอื่น ๆ เช่นC, JAVA, JavaScriptใช้การตัดทอนแทนพื้น
>>> mod = n - int(n/base) * base
ซึ่งส่งผลให้:
mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
หากท่านต้องการข้อมูลเพิ่มเติมเกี่ยวกับการปัดเศษในหลามอ่านนี้
ฉันยังคิดว่ามันเป็นพฤติกรรมแปลก ๆ ของ Python ปรากฎว่าฉันแก้การหารได้ไม่ดี (บนกระดาษ); ฉันให้ค่า 0 กับผลหารและค่า -5 สำหรับส่วนที่เหลือ แย่มาก ... ฉันลืมการแสดงตัวเลขจำนวนเต็มทางเรขาคณิต เมื่อนึกถึงเรขาคณิตของจำนวนเต็มที่กำหนดโดยเส้นจำนวนเราจะได้ค่าที่ถูกต้องสำหรับผลหารและเศษเหลือและตรวจสอบว่าพฤติกรรมของ Python นั้นใช้ได้ (แม้ว่าฉันคิดว่าคุณได้แก้ไขข้อกังวลของคุณเมื่อนานมาแล้ว)
นอกจากนี้ยังควรกล่าวถึงด้วยว่าการแบ่งใน python นั้นแตกต่างจาก C: พิจารณา
>>> x = -10
>>> y = 37
ใน C คุณคาดหวังผลลัพธ์
0
x / y ใน python คืออะไร?
>>> print x/y
-1
และ% เป็นโมดูโล - ไม่ใช่ส่วนที่เหลือ! ในขณะที่ x% y ใน C ให้ผลตอบแทน
-10
หลามให้ผล
>>> print x%y
27
คุณจะได้รับทั้งสองอย่างใน C
ส่วน:
>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0
และส่วนที่เหลือ (โดยใช้การหารจากด้านบน):
>>> r = x - d*y
>>> print r
-10
การคำนวณนี้อาจจะไม่เร็วที่สุด แต่มันใช้ได้กับการผสมเครื่องหมายของ x และ y เพื่อให้ได้ผลลัพธ์เช่นเดียวกับใน C บวกมันจะหลีกเลี่ยงคำสั่งเงื่อนไข