2010-10-07 6 views
39

que j'ai trouvé un comportement étrange en Python en ce qui concerne les nombres négatifs:L'opération modulo sur les nombres négatifs en Python

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

Quelqu'un pourrait-il expliquer ce qui se passe?

+14

ressemble à droite – wheaties

+3

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

+0

duplication possible de [C, Python - comportement différent de l'opération modulo (%)] (http://stackoverflow.com/questions/1907565/c-python-different-behaviour-of-the-modulo-operation) – nyuszika7h

Répondre

68

Contrairement à C ou C++, l'opérateur modulo de Python (%) renvoie toujours un nombre ayant le même signe que le dénominateur (diviseur). Vos rendements d'expression 3 parce

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

Il est choisi sur le comportement de C, car un résultat positif ou nul est souvent plus utile. Un exemple est de calculer les jours de la semaine. Si aujourd'hui est mardi (jour n ° 2), quel est le jour de la semaine N jours avant? En Python, nous pouvons calculer avec

return (2 - N) % 7 

mais en C, si N ≥ 3, nous obtenons un nombre négatif qui est un numéro non valide, et nous devons corriger manuellement en ajoutant 7:

int result = (2 - N) % 7; 
return result < 0 ? result + 7 : result; 

(Voir http://en.wikipedia.org/wiki/Modulo_operator pour la façon dont le signe du résultat est déterminé pour des langues différentes.)

+1

Cela ne devrait-il pas être (-2 * 4 + 3)? – Vatine

+0

@Vatine: Correction de merci. (Pensait à environ 5 ^^) – kennytm

+0

Comment émulez-vous cet opérateur très utile en C/C++? –

2

Modulo, des classes d'équivalence de 4:

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

Voici un lien vers modulo's behavior with negative numbers. (Oui, je l'ai googlé)

+0

@NullUserException - oui, c'était. fixé. Merci. – wheaties

7

Il n'existe pas de meilleure façon de gérer les divisions entières et les mods avec des nombres négatifs. Ce serait bien si a/b était la même grandeur et le signe opposé de (-a)/b. Ce serait bien si a % b était en effet un modulo b. Puisque nous voulons vraiment a == (a/b)*b + a%b, les deux premiers sont incompatibles.

Lequel garder est une question difficile, et il y a des arguments pour les deux côtés. C et C++ arrondissent la division entière vers zéro (donc a/b == -((-a)/b)), et apparemment Python ne le fait pas.

2

Comme indiqué, Python modulo fait une exception well-reasoned aux conventions d'autres langages. Cela donne un comportement transparent aux nombres négatifs, en particulier lorsqu'il est utilisé en combinaison avec l'opérateur de division d'entier //, car % modulo est souvent (comme en math.divmod):

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

Produit:

-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

Merci votre exemple m'a fait comprendre :) – Lamis

1

Je pensais aussi qu'il était un comportement étrange de Python. Il s'avère que je ne résolvais pas bien la division (sur le papier); Je donnais une valeur de 0 au quotient et une valeur de -5 au reste. Terrible ... J'ai oublié la représentation géométrique des nombres entiers. En rappelant la géométrie des entiers donnée par la ligne numérique, on peut obtenir les valeurs correctes pour le quotient et le reste, et vérifier que le comportement de Python est correct. (Bien que je suppose que vous avez déjà résolu votre problème il y a longtemps).

Questions connexes