L'opération modulo sur les nombres négatifs en Python
6 réponses
Contrairement à C ou C++, l'opérateur modulo de Python (%
) renvoie toujours un nombre ayant le même signe que le dénominateur (diviseur). Votre expression donne 3 parce que
(-5) % 4 = (-2 × 4 + 3) % 4 = 3.
Il est choisi par rapport au comportement C car un résultat non négatif est souvent plus utile. Un exemple est de calculer les jours de la semaine. Si aujourd'hui est mardi (jour # 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 nombre invalide, et nous devons le réparer manuellement en ajoutant 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(Voir http://en.wikipedia.org/wiki/Modulo_operator pour comment le signe du résultat est déterminé pour différentes langues.)
Voici une explication de Guido van Rossum:
Http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
Essentiellement, c'est pour que a/b = q avec le reste r préserve les relations b*q + r = a et 0
Il n'y a pas de meilleur moyen de gérer la division entière et les mods avec des nombres négatifs. Ce serait bien si a/b
avait la même magnitude 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 parties. C et c++ arrondissent la division entière vers zéro (donc a/b == -((-a)/b)
), et apparemment pas Python.
Comme indiqué, Python modulo fait une exception bien motivée aux conventions des autres langages.
Cela donne aux nombres négatifs un comportement transparent, en particulier lorsqu'ils sont utilisés en combinaison avec l'opérateur //
integer-divide, comme %
modulo l'est souvent (comme en mathématiques.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
- Python
%
affiche toujours zéro ou positif lorsque le diviseur est positif - Python
//
tourne toujours vers le négatif infini
Modulo, classes d'équivalence pour 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 le comportement de modulo avec des nombres négatifs . (Oui, je l'ai googlé)
Je pensais aussi que C'était un comportement étrange de Python. Il s'avère que je ne résolvais pas bien la division( sur 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és 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 préoccupation, il y a longtemps).