Listing de l'algorithme d'Euclide

I. Le formulaire
II. Le script détaillé
III. Le listing complet


Cette page présente un listing détaillé et commenté de l'implémentation de l'algorithme d'Euclide en JavaScript.

I. Le formulaire


Pour commencer, nous avons besoin d'un formulaire: deux zones de texte (a et b) pour entrer le paramètres, une troisième pour afficher le résultat, et un bouton pour lancer le calcul.
<form>
<input type="text" name="a" size=6>
<input type="text" name="b" size=6>
<input type="text" name="resultat" size=6>
<input type="button" value="Calculer" onclick="calcul(this.form)">
</form>


II. Le script détaillé


- La fonction calcul(form) :
C'est la fonction principale du programme.

Tout d'abord, elle appelle la fonction check(form), qui vérifie que la saisie est correcte, c'est-à-dire que les cases a et b contiennent bien des nombres entiers. Dans le cas contraire, le script s'arrête en affichant un message d'alerte.

Si la fonction check(form) ne décèle pas d'erreur, le script continue.

Tout d'abord, on teste si l'un au moins des entiers a et b est nul (c'est la condition eval(a*b)==0). Si c'est le cas, le script retourne la plus grande des valeurs absolues de a et b (car PGCD(a,0)=|a| pour tout entier a).
Sinon, on utilise l'algorithme d'Euclide proprement dit.

L'algorithme utilise le lemme suivant:

Lemme :

Si a, b, q et r sont des entiers relatifs tels que a=bq+r, alors PGCD(a,b)=PGCD(b,r).

On effectue donc la division euclidienne de a par b. On obtient ainsi un quotient q et un reste r. Il nous faut donc deux variables globales q et r pour cette division:
var q=0, r=0;
Si r est nul, alors PGCD(a,b)=PGCD(b,0)=|b|. Sinon, on effectue une nouvelle division euclidienne de b par r; comme on a |r|<|b|, on obtiendra un reste nul en au plus |b| étapes. Le dernier reste non nul (notons-le rn) vérifie PGCD(a,b)=PGCD(rn,0)=|rn|; la fonction doit donc retourner sa valeur absolue.

NB: Ici, la fonction de divise(a,b) ne retourne que des restes positifs; on pourrait donc envisager une fonction calcul(form) qui renverrait le dernier reste non nul, et non sa valeur absolue. Toutefois, cette valeur absolue s'avère nécéssaire dans le cas particulier où b est négatif et divise a; dans ce cas, en effet, la fonction divise(a,b) ne fait rien d'autre que retourner q=a/b et r=0, et donc le dernier reste non nul est b, et pas |b|.
function calcul(form) {
 
if (check(form)) {               //verifie la saisie
 
 
     var a=form.a.value;               //passage des parametres
     var b=form.b.value;
 
     if (eval(a*b)==0) {                    //cas particulier: PGCD(a,0)=|a|
          form.resultat.value=max(abs(eval(a)),abs(eval(b)));
          }
     else {
          for (;abs(eval(b))>0;) {                    //l'algo lui-meme
               divise(eval(a),eval(b));     //si a=bq+r avec r<b alors
               a=b;                    //PGCD(a,b)=PGCD(b,r)
               b=r;               //on continue jusqu'a r=0
               }                    //PGCD(a,b) est le dernier r non nul
          }
     form.resultat.value=abs(a);               //renvoie le resultat
     
     }
else {
     alert("Attention! vous devez entrer des entiers!");
     }
}

- La fonction divise(a,b) :

Cette fonction n'est pas optimisée, mais elle a le mérite d'être simple.

Le quotient q est initialisé à 0. La variable i indique le signe de q (positif si a et b sont de même signe, négatif sinon). La division ne pose aucun problème ici, car cette fonction n'est appelée par la fonction calcul(form) que si a et b sont tous deux non nuls.
La fonction se contente d'ajouter i à q et de soustraire ib à r jusqu'à obtenir un reste r compris dans l'intervalle [0,|b|[. Notons que l'on conserve toujours l'égalité a=bq+r.

La théorie générale nous assure de l'existence d'un couple (q,r) vérifiant a=bq+r et 0r<|b|. Or si q est non nul, si a et bq étaient de signes opposés, alors on aurait |r|=|a-bq|=|a|+|b||q||b|; donc a et bq sont de même signe, donc q est du signe du produit ab, ce qui justifie la valeur de la variable i et nous assure de trouver un couple (q,r) convenable.
function divise(a,b) {                //Division euclidienne
                         //renvoie q et r avec a=bq+r et 0<=r<|b|
 
q=0;                    //initialisation
var i=(a*b)/abs(a*b);
 
for (r=a;(r>=abs(b))||(r<0);r-=(i*b)) {
     q+=i;
     }
}

- Le fonctions max(a,b) et abs(a) :

Pas grand chose à en dire; max(a,b) retourne le plus grand des deux paramètres et abs(a) retourne la valeur absolue de a.
function max(a,b) {               //explicite...
 
if (a>=b) { return(a) }
else { return(b) }
}
 
 
function abs(a) {               //valeur absolue
return max(a,-a);
}

- Le fonctions de vérification de saisie :

La fonction isDigit(c) vérifie que son argument, un caractère, est bien un chiffre.

La fonction isInteger(s) vérifie que la chaîne de caractères passée en argument est bien un entier: le premier caractère peut être un chiffre ou un signe + ou -; les autres, s'ils existent, doivent être des chiffres.

La fonction check(form) vérifie que les champs de saisie a et b contiennent bien des entiers.
function isDigit(c) {               //verifie que c contient un chiffre
 
var test=""+c;
 
if (test=="0"||test=="1"||test=="2"||test=="3"||test=="4"||test=="5"||test=="6"||
     test=="7"||test=="8"||test=="9") {
     return true;
     }
 
return false;
 
}
 
 
function isInteger(s) {               //verifie que s contient un entier
 
var test=""+s;
 
for (var k=1;k<test.length;k++) {     //verifie que tous les caracteres sauf le premier
                         //sont des chiffres
     var c=test.substring(k,k+1);
 
     if (isDigit(c)==false) {
          return false;
          }
     }
 
return (isDigit(test.substring(0,1))||test.substring(0,1)=="+"||test.substring(0,1)=="-");
                         //le premier caractere peut etre + ou -
                         //ou un chiffre
}
 
 
function check(form) {               //verification de la saisie
 
return (isInteger(form.a.value)&&isInteger(form.b.value));
 
}

III. Le listing complet


<script language="JavaScript">
<!--
 
function isDigit(c) {               //verifie que c contient un chiffre
 
var test=""+c;
 
if (test=="0"||test=="1"||test=="2"||test=="3"||test=="4"||test=="5"||test=="6"||
     test=="7"||test=="8"||test=="9") {
     return true;
     }
 
return false;
 
}
 
 
function isInteger(s) {               //verifie que s contient un entier
 
var test=""+s;
 
for (var k=1;k<test.length;k++) {     //verifie que tous les caracteres sauf le premier
                         //sont des chiffres
     var c=test.substring(k,k+1);
 
     if (isDigit(c)==false) {
          return false;
          }
     }
 
return (isDigit(test.substring(0,1))||test.substring(0,1)=="+"||test.substring(0,1)=="-");
                         //le premier caractere peut etre + ou -
                         //ou un chiffre
}
 
 
function check(form) {               //verification de la saisie
 
return (isInteger(form.a.value)&&isInteger(form.b.value));
 
}
 
 
function max(a,b) {               //explicite...
 
if (a>=b) { return(a) }
else { return(b) }
}
 
 
function abs(a) {               //valeur absolue
return max(a,-a);
}
 
 
function divise(a,b) {                //Division euclidienne
                         //renvoie q et r avec a=bq+r et 0<=r<|b|
 
q=0;                    //initialisation
var i=(a*b)/abs(a*b);
 
for (r=a;(r>=abs(b))||(r<0);r-=(i*b)) {
     q+=i;
     }
}
 
var q=0, r=0;
 
function calcul(form) {
 
if (check(form)) {               //verifie la saisie
 
 
     var a=form.a.value;               //passage des parametres
     var b=form.b.value;
 
     if (eval(a*b)==0) {                    //cas particulier: PGCD(a,0)=a
          form.resultat.value=max(abs(eval(a)),abs(eval(b)));
          }
     else {
          for (;abs(eval(b))>0;) {                    //l'algo lui-meme
               divise(eval(a),eval(b));     //si a=bq+r avec r<b alors
               a=b;                    //PGCD(a,b)=PGCD(b,r)
               b=r;               //on continue jusqu'a r=0
               }                    //PGCD(a,b) est le dernier r non nul
          }
     form.resultat.value=abs(a);               //renvoie le resultat
     
     }
else {
     alert("Attention! vous devez entrer des entiers!");
     }
}
//-->
</script>


Première version : 30/03/97
Auteur : Arnaud Gomes-do-Vale(Page Web, e-mail :arnaud@folium.eu.org)
Source : NA
Relecture : Aucune pour l'instant.