2010-10-07 46 views
39

Tôi đã tìm thấy một số hành vi kỳ lạ trong Python về số âm:Các phép toán module trên số âm bằng Python

>>> a = -5 
>>> a % 4 
3 

bất cứ ai có thể giải thích những gì đang xảy ra?

+14

có vẻ phù hợp với tôi – wheaties

+3

'..., -9, -5, -1, 3, 7, ...' – NullUserException

+0

có thể trùng lặp của [C, Python - hành vi khác nhau của hoạt động modulo (%)] (http://stackoverflow.com/questions/1907565/c-python-different-behaviour-of-the-modulo-operation) – nyuszika7h

Trả lời

68

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 ký hiệu với mẫu số (số chia). sản lượng biểu hiện của bạn 3 vì

(-5)% 4 = (-2 × 4 + 3)% 4 = 3.

Nó được chọn thay vì các hành vi C vì kết quả không âm thường hữu dụng 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 # 2), ngày trong tuần là N ngày trước? 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 tôi có được một số âm là một số không hợp lệ, và chúng ta cần phải tự sửa chữa nó lên 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 bao dấu của kết quả được xác định cho các ngôn ngữ khác nhau.)

+1

Không phải là (-2 * 4 + 3)? – Vatine

+0

@Vatine: Cố định cảm ơn. (Đã suy nghĩ về 5 ^^) – kennytm

+0

Làm thế nào để bạn mô phỏng toán tử rất hữu ích này trong C/C++? –

22

Dưới đây là một 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, nó sao cho a/b = q với phần còn lại r giữ nguyên các mối quan hệ b * q + r = a và 0 < = r < b.

+3

Các ngôn ngữ như C++ và Java cũng giữ nguyên mối quan hệ đầu tiên, nhưng chúng ceil cho âm 'a', tích cực' b', trong khi các tầng Python. Nó luôn luôn đúng là 'abs (r)

2

Modulo, lớp tương đương 4:

  • 0: 0, 4, 8, 12 ... và -4, -8, -12 ...
  • 1: 1, 5, 9, 13 ... và -3, -7, -11 ...
  • 2: 2, 6, 10 ... và -2, -6, -10 ...
  • 3: 3, 7, 11 ... và -1, -5, -9 ...

Đây là liên kết đến modulo's behavior with negative numbers. (Có, tôi googled nó)

+0

@NullUserException - yup, đúng vậy. đã sửa. Cảm ơn. – wheaties

7

Không có cách nào tốt nhất để xử lý số nguyên và mods với số âm. Sẽ rất tuyệt nếu a/b có cùng độ lớn và ký hiệu ngược lại là (-a)/b. Nó sẽ là tốt đẹp nếu a % 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 cái đầu tiên không tương thích.

Điều gì cần giữ lại là một câu hỏi khó, và có các đối số cho cả hai bên. Phân chia số nguyên C và C++ theo hướng không (vì vậy a/b == -((-a)/b)), và dường như Python không.

2

Như đã chỉ ra, Python modulo tạo ngoại lệ well-reasoned với các quy ước của các ngôn ngữ khác. Điều này 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ử phân tách số nguyên //, như là % modulo thường là (như trong toán học.divmod):

for n in range(-8,8): 
    print n, n//4, n%4 

Tạo:

-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 
+0

Cảm ơn ví dụ của bạn đã làm cho tôi hiểu nó :) – Lamis

1

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 tốt các bộ phận (trên giấy); Tôi đã đưa ra giá trị bằng 0 cho thương và giá trị là -5 cho phần còn lại. Khủng khiếp ... 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 dạng của các số nguyên được đưa ra bởi dòng số, người ta có thể nhận được các giá trị chính xác cho thương và phần còn lại, và kiểm tra hành vi của Python là tốt. (Mặc dù tôi cho rằng bạn đã giải quyết được mối quan ngại của mình một thời gian dài trước đây).

Các vấn đề liên quan