Tôi đã tìm thấy một số hành vi kỳ lạ trong Python liên quan đến số âm:
>>> -5 % 4
3
Bất cứ ai có thể giải thích những gì đang xảy ra?
Tôi đã tìm thấy một số hành vi kỳ lạ trong Python liên quan đến số âm:
>>> -5 % 4
3
Bất cứ ai có thể giải thích những gì đang xảy ra?
..., -9, -5, -1, 3, 7, ...
math.fmod
để có được hành vi tương tự như trong C hoặc Java.
Câu trả lời:
Không giống như C hoặc C ++, toán tử modulo của Python ( %
) luôn trả về một số có cùng dấu với mẫu số (số chia). Biểu thức của bạn cho kết quả 3 vì
(-5) / 4 = -1,25 -> tầng (-1,25) = -2
(-5)% 4 = (-2 × 4 + 3)% 4 = 3.
Nó được chọn thay vì hành vi C vì kết quả không âm thường hữu ích hơn. Một ví dụ là tính toán các ngày trong tuần. Nếu hôm nay là thứ Ba (ngày thứ 2), thì ngày thứ N trước đó là thứ mấy? Trong Python, chúng ta có thể tính toán với
return (2 - N) % 7
nhưng trong C, nếu N ≥ 3, chúng ta nhận được một số âm là một số không hợp lệ và chúng ta cần sửa nó theo cách thủ công bằng cách thêm 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(Xem http://en.wikipedia.org/wiki/Modulo_operator để biết cách xác định dấu hiệu kết quả cho các ngôn ngữ khác nhau.)
Đây là lời giải thích từ Guido van Rossum:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
Về cơ bản, sao cho a / b = q với phần dư r bảo toàn các mối quan hệ b * q + r = a và 0 <= r <b.
a
, tích cực b
, trong khi các tầng Python. Điều đó luôn luôn đúng abs(r) < b
, và họ không ngại r <= 0
.
Không có cách nào tốt nhất để xử lý phép chia số nguyên và mod với số âm. Sẽ rất tốt nếu a/b
có cùng độ lớn và dấu hiệu ngược lại (-a)/b
. Sẽ rất tốt nếua % b
thực sự là một modulo b. Vì chúng tôi thực sự muốn a == (a/b)*b + a%b
, hai điều đầu tiên không tương thích.
Giữ cái nào là một câu hỏi khó, và có những tranh luận cho cả hai bên. C và C ++ phân chia số nguyên tròn về 0 (như vậy a/b == -((-a)/b)
), và rõ ràng Python thì không.
Như ra nhọn, Python modulo làm cho một nổi lập luận ngoại lệ cho các quy ước của các ngôn ngữ khác.
Điều này mang lại cho các số âm một hành vi liền mạch, đặc biệt là khi được sử dụng kết hợp với //
toán tử chia số nguyên, như %
modulo thường là (như trong toán học. Divmod ):
for n in range(-8,8):
print n, n//4, n%4
Sản xuất:
-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
%
luôn xuất ra số không hoặc số dương *//
luôn làm tròn về phía âm vô cực* ... miễn là toán hạng bên phải là số dương. Mặt khác11 % -10 == -9
Trong python , toán tử modulo hoạt động như thế này.
>>> mod = n - math.floor(n/base) * base
vì vậy kết quả là (đối với trường hợp của bạn):
mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
trong khi các ngôn ngữ khác như C, JAVA, JavaScript sử dụng hàm cắt ngắn thay vì tầng.
>>> mod = n - int(n/base) * base
kết quả là:
mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
Nếu bạn cần thêm thông tin về làm tròn trong python, hãy đọc phần này .
Modulo, các lớp tương đương cho 4:
Đây là một liên kết đến hành vi của modulo với các số âm . (Có, tôi đã tìm kiếm nó)
Tôi cũng nghĩ đó là một hành vi kỳ lạ của Python. Nó chỉ ra rằng tôi đã không giải quyết các phép chia tốt (trên giấy); Tôi đã cho giá trị 0 cho thương số và giá trị -5 cho phần còn lại. Thật kinh khủng ... Tôi đã quên biểu diễn hình học của các số nguyên. Bằng cách nhớ lại hình học của các số nguyên được cung cấp bởi trục số, người ta có thể nhận được các giá trị chính xác cho thương số và phần dư, đồng thời kiểm tra xem hoạt động của Python có ổn không. (Mặc dù tôi cho rằng bạn đã giải quyết mối quan tâm của mình từ lâu rồi).
Cũng cần phải đề cập rằng cách phân chia trong python cũng khác với C:
>>> x = -10
>>> y = 37
trong C bạn mong đợi kết quả
0
x / y trong python là gì?
>>> print x/y
-1
và% là modulo - không phải phần còn lại! Trong khi x% y trong C cho kết quả
-10
sản lượng trăn.
>>> print x%y
27
Bạn có thể nhận được cả hai như trong C
Các bộ phận:
>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0
Và phần còn lại (sử dụng phép chia từ trên):
>>> r = x - d*y
>>> print r
-10
Tính toán này có thể không phải là nhanh nhất nhưng nó hoạt động đối với bất kỳ kết hợp dấu hiệu nào của x và y để đạt được kết quả tương tự như trong C cộng với nó tránh các câu lệnh điều kiện.