143 votes

L'opération modulo sur les nombres négatifs en Python

J'ai trouvé un comportement étrange dans Python concernant les nombres négatifs :

>>> -5 % 4
3

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

35 votes

Ça me semble correct

9 votes

..., -9, -5, -1, 3, 7, ...

3 votes

175voto

KennyTM Points 232647

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

(-5) / 4 = -1,25 --> plancher(-1,25) = -2

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

Il est préféré au comportement C car un résultat non négatif est souvent plus utile. Un exemple est le calcul des jours de la semaine. Si aujourd'hui nous sommes 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 nombre non valide, et nous devons le 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 savoir comment le signe du résultat est déterminé pour différentes langues).

40voto

Kevin Points 3692

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 <= r < b.

5 votes

Des langages comme C++ et Java préservent également la première relation, mais ils plafonnent pour les valeurs négatives. a , positif b alors que les sols Python. Il est toujours vrai que abs(r) < b et ils plafonnent si r <= 0 .

22voto

Munkhbold Enkhtur Points 428

En python L'opérateur modulo fonctionne comme suit.

>>> mod = n - math.floor(n/base) * base

donc le résultat est (pour votre cas) :

mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3

alors que d'autres langues telles que C, JAVA, JavaScript utiliser la troncature au lieu du plancher.

>>> mod = n - int(n/base) * base

ce qui entraîne :

mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1

Si vous avez besoin de plus d'informations sur les arrondis en python, lisez la rubrique ce .

14voto

Deekshant Points 101

Les autres réponses, en particulier celle qui a été sélectionnée, ont clairement répondu à cette question. Mais j'aimerais présenter une approche graphique qui pourrait être plus facile à comprendre, ainsi qu'un code python pour effectuer un modulo mathématique normal en python.

Python Modulo pour les nuls

La fonction modulo est une fonction directionnelle qui décrit dans quelle mesure nous devons nous éloigner ou prendre du retard après les sauts mathématiques que nous effectuons pendant la division sur l'axe X des nombres infinis. Donc disons que vous faites 7%3

enter image description here

Donc, dans le sens direct, votre réponse serait +1, mais dans le sens inverse

enter image description here

votre réponse serait -2. Les deux réponses sont correctes. mathématiquement .

De même, vous auriez 2 modules pour les nombres négatifs. Par exemple : -7%3 peut résulter en -1 ou +2 comme indiqué -

enter image description here

Sens de la marche


enter image description here

Sens inverse


En mathématiques, on choisit des sauts vers l'intérieur, c'est-à-dire vers l'avant pour un nombre positif et vers l'arrière pour un nombre négatif.

Mais en Python, nous avons un sens direct pour toutes les opérations modulo positives. D'où votre confusion -

>>> -5 % 4 
3

>>> 5 % 4
1

Voici le code python pour le type de saut modulo en python :

def newMod(a,b):
    res = a%b
    return res if not res else res-b if a<0 else res

ce qui donnerait -

>>> newMod(-5,4)
-1

>>> newMod(5,4)
1

Beaucoup de gens s'opposent à la méthode du saut vers l'intérieur, mais mon opinion personnelle est que celle-ci est meilleure !

13voto

BobStein-VisiBone Points 398

Comme indiqué, le modulo de Python fait un bien raisonné exception aux conventions des autres langues.

Cela donne aux nombres négatifs un comportement sans faille, surtout lorsqu'ils sont utilisés en combinaison avec la fonction // opérateur de division d'entiers, comme % modulo 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 % sort toujours zéro ou positif*
  • Python // s'arrondit toujours vers l'infini négatif

* ... tant que l'opérande de droite est positif. D'autre part <code>11 % -10 == -9</code>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X