Comment utiliser l'opérateur% – Real Python

By | octobre 26, 2020

Python pas cher

Python prend en charge un large éventail d'opérateurs arithmétiques que vous pouvez utiliser lorsque vous travaillez avec des nombres dans votre code. L'un de ces opérateurs est le opérateur modulo (%), qui renvoie le reste de la division de deux nombres.

L'opérateur modulo Python peut parfois être négligé. Mais avoir une bonne compréhension de cet opérateur vous donnera un outil précieux dans votre ceinture d'outils Python.

Modulo en mathématiques

Le terme modulo provient d'une branche des mathématiques appelée arithmétique modulaire. L'arithmétique modulaire traite de l'arithmétique des nombres entiers sur une droite numérique circulaire qui a un ensemble fixe de nombres. Toutes les opérations arithmétiques effectuées sur cette droite numérique s'enrouleront lorsqu'elles atteindront un certain nombre appelé le module.

Un exemple classique de modulo en arithmétique modulaire est l'horloge de douze heures. Une horloge de douze heures a un ensemble fixe de valeurs, de 1 à 12. Lorsque vous comptez sur une horloge de douze heures, vous comptez jusqu'au module 12, puis revenez à 1. Une horloge de douze heures peut être classée comme " modulo 12 », parfois abrégé en« mod 12. »

L'opérateur modulo est utilisé lorsque vous souhaitez comparer un nombre avec le module et obtenir le nombre équivalent contraint à la plage du module.

Par exemple, supposons que vous souhaitiez déterminer l'heure à laquelle il serait neuf heures après 8h00. Sur une horloge de douze heures, vous ne pouvez pas simplement ajouter 9 à 8 car vous obtiendriez 17. Vous devez prendre le résultat, 17 , et utilise mod pour obtenir sa valeur équivalente dans un contexte de douze heures:

8 heures + 9 = 17 heures
17 mod 12 = 5

17 mod 12 Retour 5. Cela signifie que neuf heures après 8h00, c'est 17h00. Vous avez déterminé cela en prenant le nombre 17 et l'appliquer à un mod 12 le contexte.

Maintenant, si vous y pensez, 17 et 5 sont équivalents dans un mod 12 le contexte. Si vous regardiez l'aiguille des heures à 5 h et 17 h, elle serait dans la même position. L'arithmétique modulaire a une équation pour décrire cette relation:

Cette équation dit "une et b sont modulo congruents n. » Cela signifie que une et b sont équivalents en mod n car ils ont le même reste lorsqu'ils sont divisés par n. Dans l'équation ci-dessus, n est le module pour les deux une et b. Utiliser les valeurs 17 et 5 d'avant, l'équation ressemblerait à ceci:

Cela se lit "17 et 5 sont modulo congruents 12. » 17 et 5 avoir le même reste, 5, lorsqu'il est divisé par 12. Donc dans mod 12, les nombres 17 et 5 sont équivalents.

Vous pouvez le confirmer en utilisant la division:

17/12 = 1 R 5
5/12 = 0 R 5

Les deux opérations ont le même reste, 5, donc ils sont équivalents modulo 12.

Maintenant, cela peut sembler beaucoup de maths pour un opérateur Python, mais avoir ces connaissances vous préparera à utiliser l'opérateur modulo dans les exemples plus loin dans ce tutoriel. Dans la section suivante, vous examinerez les bases de l'utilisation de l'opérateur modulo Python avec les types numériques int et flotte.

Principes de base de l'opérateur Python Modulo

L'opérateur modulo, comme les autres opérateurs arithmétiques, peut être utilisé avec les types numériques int et flotte. Comme vous le verrez plus tard, il peut également être utilisé avec d'autres types comme math.fmod (), décimal.Décimalet vos propres classes.

Opérateur Modulo avec int

La plupart du temps, vous utiliserez l'opérateur modulo avec des entiers. L'opérateur modulo, lorsqu'il est utilisé avec deux entiers positifs, retournera le reste de la division euclidienne standard:

>>>

>>> 15 % 4
3

>>> 17 % 12
5

>>> 240 % 13
6

>>> dix % 16
dix

Faites attention! Tout comme avec l'opérateur de division (/), Python renverra un ZeroDivisionError si vous essayez d'utiliser l'opérateur modulo avec un diviseur de 0:

>>>

>>> 22 % 0
ZeroDivisionError: division entière ou modulo par zéro

Ensuite, vous allez examiner l'utilisation de l'opérateur modulo avec un flotte.

Opérateur Modulo avec flotte

Semblable à int, l'opérateur modulo utilisé avec un flotte renverra le reste de la division, mais comme un flotte valeur:

>>>

>>> 12,5 % 5.5
1,5

>>> 17,0 % 12,0
5,0

Une alternative à l'utilisation d'un flotte avec l'opérateur modulo est d'utiliser math.fmod () pour effectuer des opérations modulo sur flotte valeurs:

>>>

>>> importer math
>>> math.fmod(12,5, 5.5)
1,5

>>> math.fmod(8,5, 2,5)
1.0

Les documents officiels Python suggèrent d'utiliser math.fmod () sur l'opérateur modulo Python lorsque vous travaillez avec flotte valeurs à cause de la manière math.fmod () calcule le résultat de l'opération modulo. Si vous utilisez un opérande négatif, vous pouvez voir des résultats différents entre math.fmod (x, y) et x% y. Vous découvrirez l'utilisation de l'opérateur modulo avec des opérandes négatifs plus en détail dans la section suivante.

Tout comme les autres opérateurs arithmétiques, l'opérateur modulo et math.fmod () peut rencontrer des problèmes d'arrondi et de précision lors du traitement de l'arithmétique à virgule flottante:

>>>

>>> 13,3 % 1.1
0,09999999999999964

>>> importer math
>>> math.fmod(13,3, 1.1)
0,09999999999999964

Si le maintien de la précision en virgule flottante est important pour votre application, vous pouvez utiliser l'opérateur modulo avec décimal.Décimal. Vous y reviendrez plus tard dans ce didacticiel.

Opérateur modulo avec un opérande négatif

Toutes les opérations modulo que vous avez vues jusqu'à présent ont utilisé deux opérandes positifs et ont renvoyé des résultats prévisibles. Lorsqu'un opérande négatif est introduit, les choses se compliquent.

En fait, la façon dont les ordinateurs déterminent le résultat d'une opération modulo avec un opérande négatif laisse une ambiguïté quant à savoir si le reste doit prendre le signe du dividende (le nombre étant divisé) ou le signe du diviseur (le nombre par lequel le dividende est divisé). Différents langages de programmation gèrent cela différemment.

Par exemple, en JavaScript, le reste prendra le signe du dividende:

Le reste dans cet exemple, 2, est positif car il prend le signe du dividende, 8. En Python et dans d'autres langages, le reste prendra le signe du diviseur à la place:

Ici vous pouvez voir que le reste, -1, prend le signe du diviseur, -3.

Vous vous demandez peut-être pourquoi le reste en JavaScript est 2 et le reste en Python est -1. Cela a à voir avec la façon dont différentes langues déterminent le résultat d'une opération modulo. Les langues dans lesquelles le reste prend le signe du dividende utilisent l'équation suivante pour déterminer le reste:

Il y a trois variables cette équation:

  1. r est le reste.
  2. une est le dividende.
  3. n est le diviseur.

tronc () dans cette équation signifie qu'il utilise division tronquée, qui arrondira toujours un nombre négatif vers zéro. Pour plus de précisions, voir les étapes de l'opération modulo ci-dessous en utilisant 8 comme dividende et -3 comme diviseur:

r = 8 - (-3 * tronc (8 / -3))
r = 8 - (-3 * tronc (-2,666666666667))
r = 8 - (-3 * -2) # Arrondi vers 0
r = 8 - 6
r = 2

Ici, vous pouvez voir comment un langage comme JavaScript obtient le reste 2. Python et d'autres langages dans lesquels le reste prend le signe du diviseur utilisent l'équation suivante:

sol() dans cette équation signifie qu'il utilise division de plancher. Avec des nombres positifs, la division de plancher renverra le même résultat que la division tronquée. Mais avec un nombre négatif, la division par étage arrondira le résultat vers le bas, loin de zéro:

r = 8 - (-3 * plancher (8 / -3))
r = 8 - (-3 * plancher (-2,666666666667))
r = 8 - (-3 * -3) # Arrondi à partir de 0
r = 8 - 9
r = -1

Ici, vous pouvez voir que le résultat est -1.

Maintenant que vous comprenez d'où vient la différence dans le reste, vous vous demandez peut-être pourquoi cela est important si vous n'utilisez que Python. Eh bien, il s'avère que toutes les opérations modulo en Python ne sont pas identiques. Alors que le modulo utilisé avec le int et flotte les types prendront le signe du diviseur, les autres types non.

Vous pouvez voir un exemple de ceci lorsque vous comparez les résultats de 8,0% -3,0 et math.fmod (8.0, -3.0):

>>>

>>> 8,0 % -3
-1,0

>>> importer math
>>> math.fmod(8,0, -3.0)
2.0

math.fmod () prend le signe du dividende en utilisant une division tronquée, alors que flotte utilise le signe du diviseur. Plus loin dans ce didacticiel, vous verrez un autre type Python qui utilise le signe du dividende, décimal.Décimal.

Opérateur Modulo et divmod ()

Python a la fonction intégrée divmod (), qui utilise en interne l'opérateur modulo. divmod () prend deux paramètres et retourne un tuple contenant les résultats de la division de plancher et modulo en utilisant les paramètres fournis.

Voici un exemple d'utilisation divmod () avec 37 et 5:

>>>

>>> divmod(37, 5)
(7, 2)

>>> 37 // 5
7

>>> 37 % 5
2

Tu peux voir ça divmod (37, 5) renvoie le tuple (7, 2). le 7 est le résultat de la division par étage de 37 et 5. le 2 est le résultat de 37 modulo 5.

Voici un exemple dans lequel le deuxième paramètre est un nombre négatif. Comme indiqué dans la section précédente, lorsque l'opérateur modulo est utilisé avec un int, le reste prendra le signe du diviseur:

>>>

>>> divmod(37, -5)
(-8, -3)

>>> 37 // -5
-8

>>> 37 % -5
-3 # Le résultat a le signe du diviseur

Maintenant que vous avez eu la chance de voir l'opérateur modulo utilisé dans plusieurs scénarios, il est important de regarder comment Python détermine la priorité de l'opérateur modulo lorsqu'il est utilisé avec d'autres opérateurs arithmétiques.

Préséance des opérateurs modulo

Comme les autres opérateurs Python, il existe des règles spécifiques pour l'opérateur modulo qui déterminent sa priorité lors de l'évaluation des expressions. L'opérateur modulo (%) partage le même niveau de priorité que la multiplication (*), division (/) et la division au sol (//) les opérateurs.

Jetez un œil à un exemple de priorité de l'opérateur modulo ci-dessous:

>>>

>>> 4 * dix % 12 - 9
-5

Les opérateurs de multiplication et modulo ont le même niveau de priorité, donc Python les évaluera de gauche à droite. Voici les étapes de l'opération ci-dessus:

  1. 4 * 10 est évalué, ce qui entraîne 40% 12 - 9.
  2. 40% 12 est évalué, ce qui entraîne 4 - 9.
  3. 4 - 9 est évalué, ce qui entraîne -5.

Si vous souhaitez remplacer la priorité des autres opérateurs, vous pouvez utiliser des parenthèses pour entourer l'opération que vous souhaitez évaluer en premier:

>>>

>>> 4 * dix % (12 - 9)
1

Dans cet exemple, (12 - 9) est évalué en premier, suivi de 4 * 10 et enfin 40% 3, qui équivaut à 1.

Opérateur Modulo Python en pratique

Maintenant que vous avez parcouru les bases de l'opérateur modulo Python, vous allez examiner quelques exemples d'utilisation de celui-ci pour résoudre des problèmes de programmation réels. Parfois, il peut être difficile de déterminer quand utiliser l'opérateur modulo dans votre code. Les exemples ci-dessous vous donneront une idée des nombreuses façons dont il peut être utilisé.

Comment vérifier si un nombre est pair ou impair

Dans cette section, vous verrez comment utiliser l’opérateur modulo pour déterminer si un nombre est pair ou impair. Utilisation de l'opérateur modulo avec un module de 2, vous pouvez vérifier n'importe quel nombre pour voir s'il est divisible par 2. S'il est divisible de manière égale, il s'agit d'un nombre pair.

Jeter un coup d'œil à est même() qui vérifie si le num le paramètre est pair:

def est même(num):
    revenir num % 2 == 0

Ici num% 2 sera égal 0 si num est pair et 1 si num est impair. Vérification contre 0 renverra un booléen de Vrai ou Faux selon que oui ou non num est même.

La vérification des nombres impairs est assez similaire. Pour vérifier un nombre impair, vous inversez le contrôle d'égalité:

def est impair(num):
    revenir num % 2 ! = 0

Cette fonction retournera Vrai si num% 2 n'est pas égal 0, ce qui signifie qu'il y a un reste prouvant num est un nombre impair. Maintenant, vous vous demandez peut-être si vous pouvez utiliser la fonction suivante pour déterminer si num est un nombre impair:

def est impair(num):
    revenir num % 2 == 1

La réponse à cette question est oui et non. Techniquement, cette fonction fonctionnera avec la façon dont Python calcule modulo avec des entiers. Cela dit, évitez de comparer le résultat d'une opération modulo avec 1 car toutes les opérations modulo en Python ne renverront pas le même reste.

Vous pouvez voir pourquoi dans les exemples suivants:

>>>

>>> -3 % 2
1

>>> 3 % -2
-1

Dans le deuxième exemple, le reste prend le signe du diviseur négatif et renvoie -1. Dans ce cas, la vérification booléenne 3% -2 == 1 retournerais Faux.

Cependant, si vous comparez l'opération modulo avec 0, alors peu importe quel opérande est négatif. Le résultat sera toujours Vrai lorsqu'il s'agit d'un nombre pair:

>>>

>>> -2 % 2
0

>>> 2 % -2
0

Si vous vous en tenez à comparer une opération modulo Python avec 0, alors vous ne devriez pas avoir de problèmes pour vérifier les nombres pairs et impairs ou tout autre multiple d'un nombre dans votre code.

Dans la section suivante, vous découvrirez comment vous pouvez utiliser l'opérateur modulo avec des boucles pour contrôler le flux de votre programme.

Comment exécuter du code à des intervalles spécifiques dans une boucle

Avec l'opérateur modulo Python, vous pouvez exécuter du code à des intervalles spécifiques dans une boucle. Cela se fait en effectuant une opération modulo avec l'indice actuel de la boucle et un module. Le numéro de module détermine la fréquence à laquelle le code spécifique à l'intervalle s'exécutera dans la boucle.

Voici un exemple:

def split_names_into_rows(liste de nom, module=3):
    pour indice, Nom dans énumérer(liste de nom, début=1):
        impression(F"Nom:- ^ 15    ", fin="")
        si indice % module == 0:
            impression()
    impression()

Ce code définit split_names_into_rows (), qui prend deux paramètres. liste de nom est une liste de noms qui doivent être divisés en lignes. module définit un module pour l'opération, déterminant effectivement le nombre de noms devant figurer dans chaque ligne. split_names_into_rows () bouclera liste de nom et commencez une nouvelle ligne après avoir atteint le module valeur.

Avant de décomposer la fonction plus en détail, regardez-la en action:

>>>

>>> des noms = [[[["Picard", "Riker", "Troi", "Broyeur", "Worf", "Les données", "La Forge"]
>>> split_names_into_rows(des noms)
---- Picard ----- ----- Riker ----- ----- Troi ------
---- Concasseur ---- ----- Worf ------ ----- Données ------
--- La Forge ----

Comme vous pouvez le voir, la liste des noms a été divisée en trois lignes, avec un maximum de trois noms dans chaque ligne. module par défaut 3, mais vous pouvez spécifier n'importe quel nombre:

>>>

>>> split_names_into_rows(des noms, module=4)
---- Picard ----- ----- Riker ----- ----- Troi ------ ---- Concasseur ----
----- Worf ------ ----- Données ------ --- La Forge ----

>>> split_names_into_rows(des noms, module=2)
---- Picard ----- ----- Riker -----
----- Troi ------ ---- Concasseur ----
----- Worf ------ ----- Données ------
--- La Forge ----

>>> split_names_into_rows(des noms, module=1)
---- Picard -----
----- Riker -----
----- Troi ------
----Broyeur----
----- Worf ------
-----Les données------
--- La Forge ----

Maintenant que vous avez vu le code en action, vous pouvez décomposer ce qu’il fait. Premièrement, il utilise énumérer itérer sur liste de nom, affectant l'élément actuel de la liste à Nom et une valeur de comptage à indice. Vous pouvez voir que l'option début argument pour énumérer est réglé sur 1. Cela signifie que le indice le compte commencera à 1 au lieu de 0:

pour indice, Nom dans énumérer(liste de nom, début=1):

Ensuite, à l'intérieur de la boucle, la fonction appelle impression() pour sortir Nom à la ligne actuelle. le fin paramètre pour impression() est une chaîne vide ("") afin qu'il ne génère pas de nouvelle ligne à la fin de la chaîne. Une f-string est passée à impression(), qui utilise la syntaxe de formatage de sortie de chaîne fournie par Python:

impression(F"Nom:- ^ 15    ", fin="")

Sans entrer dans les détails, le : - ^ 15 la syntaxe dit impression() pour faire ce qui suit:

  • Sortie au moins 15 caractères, même si la chaîne est inférieure à 15 caractères.
  • Alignez la chaîne au centre.
  • Remplissez n'importe quel espace à droite ou à gauche de la chaîne avec le trait d'union (-).

Maintenant que le nom a été imprimé sur la ligne, jetez un œil à la partie principale de split_names_into_rows ():

si indice % module == 0:
    impression()

Ce code prend l'itération actuelle indice et, en utilisant l'opérateur modulo, le compare avec module. Si le résultat est égal à 0, puis il peut exécuter du code spécifique à l'intervalle. Dans ce cas, la fonction appelle impression() pour ajouter une nouvelle ligne, qui commence une nouvelle ligne.

Le code ci-dessus n'est qu'un exemple. Utilisation du motif indice% module == 0 vous permet d'exécuter différents codes à des intervalles spécifiques dans vos boucles. Dans la section suivante, vous allez pousser ce concept un peu plus loin et examiner l'itération cyclique.

Comment créer une itération cyclique

Itération cyclique décrit un type d'itération qui se réinitialisera une fois atteint un certain point. Généralement, ce type d'itération est utilisé pour restreindre l'index de l'itération à une certaine plage.

Vous pouvez utiliser l'opérateur modulo pour créer une itération cyclique. Jetez un œil à un exemple utilisant le tortue bibliothèque pour dessiner une forme:

importer tortue
importer Aléatoire

def draw_with_cyclic_iteration():
    couleurs = [[[["vert", "cyan", "Orange", "violet", "rouge", "Jaune", "blanc"]

    tortue.bgcolor("gray8") # Hex: # 333333
    tortue.pendre()
    tortue.couleur de crayon(Aléatoire.choix(couleurs)) # La première couleur est aléatoire

    je = 0 # Index initial

    tandis que Vrai:
        je = (je + 1) % 6 # Mettre à jour l'index
        tortue.penser(je) # Définir la taille du stylo sur i
        tortue.vers l'avant(225)
        tortue.droite(170)

        # Choisissez une couleur aléatoire
        si je == 0:
            tortue.couleur de crayon(Aléatoire.choix(couleurs))

Le code ci-dessus utilise une boucle infinie pour dessiner une forme d'étoile répétitive. Toutes les six itérations, il change la couleur du stylo. La taille du stylo augmente à chaque itération jusqu'à je est réinitialisé à 0. Si vous exécutez le code, vous devriez obtenir quelque chose de similaire à ceci:

Exemple d'itération cyclique à l'aide de l'opérateur Python mod (%)

Les parties importantes de ce code sont mises en évidence ci-dessous:

importer tortue
importer Aléatoire

def draw_with_cyclic_iteration():
    couleurs = [[[["vert", "cyan", "Orange", "violet", "rouge", "Jaune", "blanc"]

    tortue.bgcolor("gray8") # Hex: # 333333
    tortue.pendre()
    tortue.couleur de crayon(Aléatoire.choix(couleurs))

    je = 0 # Index initial

    tandis que Vrai:
        je = (je + 1) % 6 # Mettre à jour l'index
        tortue.penser(je) # Définir la taille du stylo sur i
        tortue.vers l'avant(225)
        tortue.droite(170)

        # Choisissez une couleur aléatoire
        si je == 0:
            tortue.couleur de crayon(Aléatoire.choix(couleurs))

À chaque fois dans la boucle, je est mis à jour en fonction des résultats de (i + 1)% 6. Cette nouvelle je valeur est utilisée pour augmenter la .pensize à chaque itération. Une fois que je atteint 5, (i + 1)% 6 sera égal 0, et je sera réinitialisé à 0.

Vous pouvez voir les étapes de l'itération ci-dessous pour plus de précisions:

i = 0: (0 + 1)% 6 = 1
i = 1: (1 + 1)% 6 = 2
i = 2: (2 + 1)% 6 = 3
i = 3: (3 + 1)% 6 = 4
i = 4: (4 + 1)% 6 = 5
i = 5: (5 + 1)% 6 = 0 # Réinitialiser

Quand je est réinitialisé à 0, le .pencolor change à une nouvelle couleur aléatoire comme indiqué ci-dessous:

si je == 0:
    tortue.couleur de crayon(Aléatoire.choix(couleurs))

Le code de cette section utilise 6 comme module, mais vous pouvez le définir sur n'importe quel nombre pour ajuster le nombre d'itérations de la boucle avant de réinitialiser la valeur je.

Comment convertir des unités

Dans cette section, vous allez voir comment vous pouvez utiliser l'opérateur modulo pour convertir des unités. Les exemples suivants prennent des unités plus petites et les convertissent en unités plus grandes sans utiliser de décimales. L'opérateur modulo est utilisé pour déterminer tout reste qui peut exister lorsque l'unité la plus petite n'est pas divisible uniformément par l'unité la plus grande.

Dans ce premier exemple, vous allez convertir des pouces en pieds. L'opérateur modulo est utilisé pour obtenir les pouces restants qui ne se divisent pas uniformément en pieds. L'opérateur de division d'étage (//) est utilisé pour arrondir le total des pieds:

def convert_inches_to_feet(total_inches):
    pouces = total_inches % 12
    pieds = total_inches // 12

    impression(F"total_inches    pouces = pieds    pieds et pouces    pouces")

Voici un exemple de la fonction utilisée:

>>>

>>> convert_inches_to_feet(450)
450 pouces = 37 pieds et 6 pouces

Comme vous pouvez le voir sur la sortie, 450% 12 Retour 6, qui sont les pouces restants qui n’ont pas été divisés en pieds. Le résultat de 450 // 12 est 37, qui est le nombre total de pieds par lequel les pouces ont été répartis également.

Vous pouvez aller un peu plus loin dans cet exemple suivant. convert_minutes_to_days () prend un entier, total_mins, représentant un nombre de minutes et affiche la période en jours, heures et minutes:

def convert_minutes_to_days(total_mins):
    journées = total_mins // 1440
    extra_minutes = total_mins % 1440

    heures = extra_minutes // 60
    minutes = extra_minutes % 60

    impression(F"total_mins    = journées    journées, heures    heures, et minutes    minutes")

En décomposant cela, vous pouvez voir que la fonction effectue les opérations suivantes:

  1. Détermine le nombre total de jours divisibles uniformément avec total_mins // 1440, où 1440 est le nombre de minutes dans une journée
  2. Calcule tout extra_minutes laissé avec total_mins% 1440
  3. Utilise le extra_minutes pour obtenir le même divisible heures et tout extra minutes

Vous pouvez voir comment cela fonctionne ci-dessous:

>>>

>>> convert_minutes_to_days(1503)
1503 = 1 jour, 1 heure et 3 minutes

>>> convert_minutes_to_days(3456)
3456 = 2 jours, 9 heures et 36 minutes

>>> convert_minutes_to_days(35 000)
35000 = 24 jours, 7 heures et 20 minutes

Bien que les exemples ci-dessus ne traitent que de la conversion des pouces en pieds et des minutes en jours, vous pouvez utiliser n'importe quel type d'unités avec l'opérateur modulo pour convertir une unité plus petite en une unité plus grande.

Maintenant que vous avez vu comment utiliser l'opérateur modulo pour convertir des unités, dans la section suivante, vous allez voir comment vous pouvez utiliser l'opérateur modulo pour vérifier les nombres premiers.

Comment déterminer si un nombre est un nombre premier

Dans cet exemple suivant, vous allez voir comment vous pouvez utiliser l'opérateur modulo Python pour vérifier si un nombre est un nombre premier. Un nombre premier est un nombre qui ne contient que deux facteurs, 1 et lui-même. Quelques exemples de nombres premiers sont 2, 3, 5, 7, 23, 29, 59, 83, et 97.

Le code ci-dessous est une implémentation pour déterminer la primalité d'un nombre à l'aide de l'opérateur modulo:

def check_prime_number(num):
    si num < 2:
        impression(F"num    doit être supérieur ou égal à 2 pour être premier. ")
        revenir

    facteurs = [([([([(1, num)]
    je = 2

    tandis que je * je <= num:
        si num % je == 0:
            facteurs.ajouter((je, num//je))
        je + = 1

    si len(facteurs) > 1:
        impression(F"num    n'est pas primordial. Il a les facteurs suivants: facteurs")
    autre:
        impression(F"num    est un nombre premier ")

Ce code définit check_prime_number (), qui prend le paramètre num et vérifie s'il s'agit d'un nombre premier. Si tel est le cas, un message s'affiche indiquant que num est un nombre premier. S'il ne s'agit pas d'un nombre premier, un message s'affiche avec tous les facteurs du nombre.

Avant de regarder de plus près la fonction, voici les résultats en utilisant différents nombres:

>>>

>>> check_prime_number(44)
44 n'est pas premier. Il a les facteurs suivants: [(1, 44), (2, 22), (4, 11)]

>>> check_prime_number(53)
53 est un nombre premier

>>> check_prime_number(115)
115 n'est pas premier. Il a les facteurs suivants: [(1, 115), (5, 23)]

>>> check_prime_number(997)
997 est un nombre premier

En creusant dans le code, vous pouvez voir qu'il commence en vérifiant si num est inférieur à 2. Les nombres premiers ne peuvent être supérieurs ou égaux à 2. Si num est inférieur à 2, la fonction n’a pas besoin de continuer. Ce sera impression() un message et revenir:

si num < 2:
    impression(F"num    doit être supérieur ou égal à 2 pour être premier. ")
    revenir

Si num est supérieur à 2, alors la fonction vérifie si num est un nombre premier. Pour vérifier cela, la fonction itère sur tous les nombres entre 2 et la racine carrée de num pour voir si l'un se divise uniformément en num. Si l'un des nombres se divise uniformément, un facteur a été trouvé, et num ne peut pas être un nombre premier.

Voici la partie principale de la fonction:

facteurs = [([([([(1, num)]
je = 2

tandis que je * je <= num:
    si num % je == 0:
        facteurs.ajouter((je, num//je))
    je + = 1

Il y a beaucoup de choses à déballer ici, alors allons-y étape par étape.

Tout d'abord, un facteurs la liste est créée avec les facteurs initiaux, (1, num). Cette liste sera utilisée pour stocker tous les autres facteurs trouvés:

Ensuite, en commençant par 2, le code s'incrémente je jusqu'à ce qu'il atteigne la racine carrée de num. À chaque itération, il compare num avec je pour voir s’il est divisible de manière égale. Le code doit uniquement vérifier jusqu'à et y compris la racine carrée de num car il ne contiendrait aucun facteur supérieur à ceci:

je = 2

tandis que je * je <= num:
    si num % je == 0:
        facteurs.ajouter((je, num//je))
    je + = 1

Au lieu d'essayer de déterminer la racine carrée de num, la fonction utilise un tandis que boucle pour voir si i * i <= num. Aussi longtemps que i * i <= num, la boucle n'a pas atteint la racine carrée de num.

À l'intérieur de tandis que boucle, l'opérateur modulo vérifie si num est divisible par je:

facteurs = [([([([(1, num)]
je = 2 # Démarrer l'index initial à 2

tandis que je * je <= num:
    si num % je == 0:
        facteurs.ajouter((je, num//je))
    je + = 1

Si num est divisible par je, puis je est un facteur de num, et un tuple des facteurs est ajouté au facteurs liste.

Une fois la tandis que boucle est terminée, le code vérifie si des facteurs supplémentaires ont été trouvés:

si len(facteurs) > 1:
    impression(F"num    n'est pas primordial. Il a les facteurs suivants: facteurs")
autre:
    impression(F"num    est un nombre premier ")

If more than one tuple exists in the factors list, then num can’t be a prime number. For nonprime numbers, the factors are printed out. For prime numbers, the function prints a message stating that num is a prime number.

How to Implement Ciphers

The Python modulo operator can be used to create ciphers. A cipher is a type of algorithm for performing encryption and decryption on an input, usually text. In this section, you’ll look at two ciphers, the Caesar cipher et le Vigenère cipher.

Caesar Cipher

The first cipher that you’ll look at is the Caesar cipher, named after Julius Caesar, who used it to secretly communicate messages. It’s a substitution cipher that uses letter substitution to encrypt a string of text.

The Caesar cipher works by taking a letter to be encrypted and shifting it a certain number of positions to the left or right in the alphabet. Whichever letter is in that position is used as the encrypted character. This same shift value is applied to all characters in the string.

For example, if the shift were 5, then UNE would shift up five letters to become F, B would become G, and so on. Below you can see the encryption process for the text REALPYTHON with a shift of 5:

Caesar Cipher using Python mod (%) Operator

The resulting cipher is WJFQUDYMTS.

Decrypting the cipher is done by reversing the shift. Both the encryption and decryption processes can be described with the following expressions, where char_index is the index of the character in the alphabet:

encrypted_char_index = (char_index + shift) % 26
decrypted_char_index = (char_index - shift) % 26

This cipher uses the modulo operator to make sure that, when shifting a letter, the index will wrap around if the end of the alphabet is reached. Now that you know how this cipher works, take a look at an implementation:

import chaîne

def caesar_cipher(text, shift, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha():
        raise ValueError("Text must be ASCII and contain no numbers.")

    lowercase = chaîne.ascii_lowercase
    uppercase = chaîne.ascii_uppercase
    result = ""

    si decrypt:
        shift = shift * -1

    pour char dans text:
        si char.islower():
            index = lowercase.index(char)
            result += lowercase[([([([(index + shift) % 26]
        else:
            index = uppercase.index(char)
            result += uppercase[([([([(index + shift) % 26]

    revenir result

This code defines a function called caesar_cipher(), which has two required parameters and one optional parameter:

  • text is the text to be encrypted or decrypted.
  • shift is the number of positions to shift each letter.
  • decrypt is a Boolean to set if text should be decrypted.

decrypt is included so that a single function can be used to handle both encryption and decryption. This implementation can handle only alphabetic characters, so the function first checks that text is an alphabetic character in the ASCII encoding:

def caesar_cipher(text, shift, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha():
        raise ValueError("Text must be ASCII and contain no numbers.")

The function then defines three variables to store the lowercase ASCII characters, the uppercase ASCII characters, and the results of the encryption or decryption:

lowercase = chaîne.ascii_lowercase # "abcdefghijklmnopqrstuvwxyz"
uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = ""

Next, if the function is being used to decrypt text, then it multiplies shift par -1 to make it shift backward:

si decrypt:
    shift = shift * -1

Finalement, caesar_cipher() loops over the individual characters in text and performs the following actions for each char:

  1. Check if char is lowercase or uppercase.
  2. Get the index du char in either the lowercase ou uppercase ASCII lists.
  3. Add a shift to this index to determine the index of the cipher character to use.
  4. Utilisation % 26 to make sure the shift will wrap back to the start of the alphabet.
  5. Append the cipher character to the result string.

After the loop finishes iterating over the text value, the result is returned:

pour char dans text:
    si char.islower():
        index = lowercase.index(char)
        result += lowercase[([([([(index + shift) % 26]
    else:
        index = uppercase.index(char)
        result += uppercase[([([([(index + shift) % 26]

revenir result

Here’s the full code again:

import chaîne

def caesar_cipher(text, shift, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha():
        raise ValueError("Text must be ASCII and contain no numbers.")

    lowercase = chaîne.ascii_lowercase
    uppercase = chaîne.ascii_uppercase
    result = ""

    si decrypt:
        shift = shift * -1

    pour char dans text:
        si char.islower():
            index = lowercase.index(char)
            result += lowercase[([([([(index + shift) % 26]
        else:
            index = uppercase.index(char)
            result += uppercase[([([([(index + shift) % 26]

    revenir result

Now run the code in the Python REPL using the text meetMeAtOurHideOutAtTwo with a shift of dix:

>>>

>>> caesar_cipher("meetMeAtOurHideOutAtTwo", dix)
woodWoKdYebRsnoYedKdDgy

The encrypted result is woodWoKdYebRsnoYedKdDgy. Using this encrypted text, you can run the decryption to get the original text:

>>>

>>> caesar_cipher("woodWoKdYebRsnoYedKdDgy", dix, decrypt=True)
meetMeAtOurHideOutAtTwo

The Caesar cipher is fun to play around with for an introduction to cryptography. While the Caesar cipher is rarely used on its own, it’s the basis for more complex substitution ciphers. In the next section, you’ll look at one of the Caesar cipher’s descendants, the Vigenère cipher.

Vigenère Cipher

The Vigenère cipher is a polyalphabetic substitution cipher. To perform its encryption, it employs a different Caesar cipher for each letter of the input text. The Vigenère cipher uses a keyword to determine which Caesar cipher should be used to find the cipher letter.

You can see an example of the encryption process in the following image. In this example, the input text REALPYTHON is encrypted using the keyword MODULO:

Vigenère Cipher using Python mod (%) Operator

For each letter of the input text, REALPYTHON, a letter from the keyword MODULO is used to determine which Caesar cipher column should be selected. If the keyword is shorter than the input text, as is the case with MODULO, then the letters of the keyword are repeated until all letters of the input text have been encrypted.

Below is an implementation of the Vigenère cipher. As you’ll see, the modulo operator is used twice in the function:

import chaîne

def vigenere_cipher(text, key, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
        raise ValueError("Text must be uppercase ASCII without numbers.")

    uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    résultats = ""

    pour je, char dans enumerate(text):
        current_key = key[[[[je % len(key)]
        char_index = uppercase.index(char)
        key_index = uppercase.index(current_key)

        si decrypt:
            index = char_index - key_index + 26
        else:
            index = char_index + key_index

        résultats += uppercase[[[[index % 26]

    revenir résultats

You may have noticed that the signature for vigenere_cipher() is quite similar to caesar_cipher() from the previous section:

def vigenere_cipher(text, key, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
        raise ValueError("Text must be uppercase ASCII without numbers.")

    uppercase = chaîne.ascii_uppercase
    résultats = ""

The main difference is that, instead of a shift parameter, vigenere_cipher() takes a key parameter, which is the keyword to be used during encryption and decryption. Another difference is the addition of text.isupper(). Based on this implementation, vigenere_cipher() can only accept input text that is all uppercase.

Comme caesar_cipher(), vigenere_cipher() iterates over each letter of the input text to encrypt or decrypt it:

pour je, char dans enumerate(text):
    current_key = key[[[[je % len(key)]

In the above code, you can see the function’s first use of the modulo operator:

current_key = key[[[[je % len(key)]

Here, the current_key value is determined based on an index returned from i % len(key). This index is used to select a letter from the key string, such as M de MODULO.

The modulo operator allows you to use any length keyword regardless of the length of the text to be encrypted. Once the index je, the index of the character currently being encrypted, equals the length of the keyword, it will start over from the beginning of the keyword.

For each letter of the input text, several steps determine how to encrypt or decrypt it:

  1. Determine the char_index based on the index of char inside uppercase.
  2. Determine the key_index based on the index of current_key inside uppercase.
  3. Utilisation char_index et key_index to get the index for the encrypted or decrypted character.

Take a look at these steps in the code below:

char_index = uppercase.index(char)
key_index = uppercase.index(current_key)

si decrypt:
    index = char_index - key_index + 26
else:
    index = char_index + key_index

You can see that the indices for decryption and encryption are calculated differently. Voilà pourquoi decrypt is used in this function. This way, you can use the function for both encryption and decryption.

After the index is determined, you find the function’s second use of the modulo operator:

résultats += uppercase[[[[index % 26]

index % 26 ensures that the index of the character doesn’t exceed 25, thus making sure it stays inside the alphabet. With this index, the encrypted or decrypted character is selected from uppercase and appended to résultats.

Here’s the full code the Vigenère cipher again:

import chaîne

def vigenere_cipher(text, key, decrypt=False):
    si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
        raise ValueError("Text must be uppercase ASCII without numbers.")

    uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    résultats = ""

    pour je, char dans enumerate(text):
        current_key = key[[[[je % len(key)]
        char_index = uppercase.index(char)
        key_index = uppercase.index(current_key)

        si decrypt:
            index = char_index - key_index + 26
        else:
            index = char_index + key_index

        résultats += uppercase[[[[index % 26]

    revenir résultats

Now go ahead and run it in the Python REPL:

>>>

>>> vigenere_cipher(text="REALPYTHON", key="MODULO")
DSDFAMFVRH

>>> encrypted = vigenere_cipher(text="REALPYTHON", key="MODULO")
>>> impression(encrypted)
DSDFAMFVRH

>>> vigenere_cipher(encrypted, "MODULO", decrypt=True)
REALPYTHON

Agréable! You now have a working Vigenère cipher for encrypting text strings.

Python Modulo Operator Advanced Uses

In this final section, you’ll take your modulo operator knowledge to the next level by using it with decimal.Decimal. You’ll also look at how you can add .__mod__() to your custom classes so they can be used with the modulo operator.

Using the Python Modulo Operator With decimal.Decimal

Earlier in this tutorial, you saw how you can use the modulo operator with numeric types like int et float as well as with math.fmod(). You can also use the modulo operator with Decimal from the decimal module. You use decimal.Decimal when you want discrete control of the precision of floating-point arithmetic operations.

Here are some examples of using whole integers with decimal.Decimal and the modulo operator:

>>>

>>> import decimal
>>> decimal.Decimal(15) % decimal.Decimal(4)
Decimal('3')

>>> decimal.Decimal(240) % decimal.Decimal(13)
Decimal('6')

Here are some floating-point numbers used with decimal.Decimal and the modulo operator:

>>>

>>> decimal.Decimal("12.5") % decimal.Decimal("5.5")
Decimal('1.5')

>>> decimal.Decimal("13.3") % decimal.Decimal("1.1")
Decimal('0.1')

All modulo operations with decimal.Decimal return the same results as other numeric types, except when one of the operands is negative. Unlike int et float, but like math.fmod(), decimal.Decimal uses the sign of the dividend for the results.

Take a look at the examples below comparing the results of using the modulo operator with standard int et float values and with decimal.Decimal:

>>>

>>> -17 % 3
1 # Sign of the divisor

>>> decimal.Decimal(-17) % decimal.Decimal(3)
Decimal(-2) # Sign of the dividend

>>> 17 % -3
-1 # Sign of the divisor

>>> decimal.Decimal(17) % decimal.Decimal(-3)
Decimal("2") # Sign of dividend

>>> -13.3 % 1.1
1.0000000000000004 # Sign of the divisor

>>> decimal.Decimal("-13.3") % decimal.Decimal("1.1")
Decimal("-0.1") # Sign of the dividend

Compared with math.fmod(), decimal.Decimal will have the same sign, but the precision will be different:

>>>

>>> decimal.Decimal("-13.3") % decimal.Decimal("1.1")
Decimal("-0.1")

>>> math.fmod(-13.3, 1.1)
-0.09999999999999964

As you can see from the above examples, working with decimal.Decimal and the modulo operator is similar to working with other numeric types. You just need to keep in mind how it determines the sign of the result when working with a negative operand.

In the next section, you’ll look at how you can override the modulo operator in your classes to customize its behavior.

Using the Python Modulo Operator With Custom Classes

The Python data model allows to you override the built-in methods in a Python object to customize its behavior. In this section, you’ll look at how to override .__mod__() so that you can use the modulo operator with your own classes.

For this example, you’ll be working with a Étudiant class. This class will track the amount of time a student has studied. Here’s the initial Étudiant class:

class Étudiant:
    def __init__(self, name):
        self.name = name
        self.study_sessions = []

    def add_study_sessions(self, sessions):
        self.study_sessions += sessions

le Étudiant class is initialized with a name parameter and starts with an empty list, study_sessions, which will hold a list of integers representing minutes studied per session. There’s also .add_study_sessions(), which takes a sessions parameter that should be a list of study sessions to add to study_sessions.

Now, if you remember from the converting units section above, convert_minutes_to_day() used the Python modulo operator to convert total_mins into days, hours, and minutes. You’ll now implement a modified version of that method to see how you can use your custom class with the modulo operator:

def total_study_time_in_hours(student, total_mins):
    heures = total_mins // 60
    minutes = total_mins % 60

    impression(F"student.name    studied heures    hours and minutes    minutes")

You can use this function with the Étudiant class to display the total hours a Étudiant has studied. Combined with the Étudiant class above, the code will look like this:

class Étudiant:
    def __init__(self, name):
        self.name = name
        self.study_sessions = []

    def add_study_sessions(self, sessions):
        self.study_sessions += sessions

def total_study_time_in_hours(student, total_mins):
    heures = total_mins // 60
    minutes = total_mins % 60

    impression(F"student.name    studied heures    hours and minutes    minutes")

If you load this module in the Python REPL, then you can use it like this:

>>>

>>> jane = Étudiant("Jane")
>>> jane.add_study_sessions([[[[120, 30, 56, 260, 130, 25, 75])
>>> total_mins = sum(jane.study_sessions)
>>> total_study_time_in_hours(jane, total_mins)
Jane studied 11 hours and 36 minutes

The above code prints out the total hours jane studied. This version of the code works, but it requires the extra step of summing study_sessions to get total_mins before calling total_study_time_in_hours().

Here’s how you can modify the Étudiant class to simplify the code:

class Étudiant:
    def __init__(self, name):
        self.name = name
        self.study_sessions = []

    def add_study_sessions(self, sessions):
        self.study_sessions += sessions

    def __mod__(self, autre):
        revenir sum(self.study_sessions) % autre

    def __floordiv__(self, autre):
        revenir sum(self.study_sessions) // autre

By overriding .__mod__() et .__floordiv__(), you can use a Étudiant instance with the modulo operator. Calculating the sum() de study_sessions is included in the Étudiant class as well.

With these modifications, you can use a Étudiant instance directly in total_study_time_in_hours(). Comme total_mins is no longer needed, you can remove it:

def total_study_time_in_hours(student):
    heures = student // 60
    minutes = student % 60

    impression(F"student.name    studied heures    hours and minutes    minutes")

Here’s the full code after modifications:

class Étudiant:
    def __init__(self, name):
        self.name = name
        self.study_sessions = []

    def add_study_sessions(self, sessions):
        self.study_sessions += sessions

    def __mod__(self, autre):
        revenir sum(self.study_sessions) % autre

    def __floordiv__(self, autre):
        revenir sum(self.study_sessions) // autre

def total_study_time_in_hours(student):
    heures = student // 60
    minutes = student % 60

    impression(F"student.name    studied heures    hours and minutes    minutes")

Now, calling the code in the Python REPL, you can see it’s much more succinct:

>>>

>>> jane = Étudiant("Jane")
>>> jane.add_study_sessions([[[[120, 30, 56, 260, 130, 25, 75])
>>> total_study_time_in_hours(jane)
Jane studied 11 hours and 36 minutes

By overriding .__mod__(), you allow your custom classes to behave more like Python’s built-in numeric types.

Conclusion

At first glance, the Python modulo operator may not grab your attention. Yet, as you’ve seen, there’s so much to this humble operator. From checking for even numbers to encrypting text with ciphers, you’ve seen many different uses for the modulo operator.

In this tutorial, you’ve learned how to:

  • Use the modulo operator with int, float, math.fmod(), divmod(), et decimal.Decimal
  • Calculate the results of a modulo operation
  • Solve real-world problems using the modulo operator
  • Override .__mod__() in your own classes to use them with the modulo operator

With the knowledge you’ve gained in this tutorial, you can now start using the modulo operator in your own code with great success. Happy Pythoning!