Au collège, on s'en sert habituellement lorsque y est un nombre entier. Voici un rappel de quelques règles :
On peut déjà formuler certaines remarques qui vont rester vraies lorsque y ne sera pas entier :
function puissance(x,y)
{
if(y>0)
{
/* On s'occupera de programmer plus tard un sous-programme
de calcul de x^y avec y>0 ; voir [Remarque 4]. */
}
else
{
if(x==0)return "Non défini !";// x = 0 et y ≤ 0 <=> x^y n'est pas défini ; Voir [Remarque 1].
if(y<0)
{
return 1/puissance(x,-y);// x^y = 1/(x^-y) ; Voir [Remarque 3].
}
else
return 1;// x^0 = 1 ; Voir [Remarque 2].
}
}
Occupons-nous donc maintenant du sous-programme (dans la suite, on parlera donc toujours des cas où y est strictement positif), celui-ci va lui-même être découpé en sous-programmes. Premièrement, avec les deux égalités x1 = x et xy = x × xy - 1 on peut trouver xy pour tous les y entiers :
function puissance(x,y)
{
if(y>0)
{
if(y==Math.round(y))
{
/* y est entier, on utilise la formule */
return (y==1?x:x*puissance(x,y-1));
}
else
{
/* y non entier, à compléter plus tard... */
}
}
else
return (x==0?"Non défini !":(y<0?1/puissance(x,-y):1));// J'ai condensé l'écriture !
}
Étudions maintenant le cas où 0 < y < 1 : si on arrive à trouver un algorithme pour ce cas, alors on aura xy = xy1 + y2 = xy1 × xy2 avec y1 nombre entier et 0 < y2 < 1 et on pourra calculer pour tous les y. (Je rappelle que l'on ne s'occupe ici que des y > 0)
Soit donc z = 1/y l'inverse de y. On a (xy)z = xy × z = x1 = x. Ce qui signifie que xy est la racine z_ième de de x. Pour la trouver il suffit de chercher un nombre qui élevé à la puissance z donnera x. Le paradoxe se situe dans le fait que l'on ne sait pas encore faire cette élévation à la puissance z pour tous les z !
Non seulement il faut que z soit entier pour que l'on soit en mesure de trouver le résultat mais aussi si x est négatif, la racine recherchée n'est pas toujours réelle. Regardons d'un peu plus près ce dernier cas...
Posons donc x = -n avec n > 0. (-n)y = (-1 × n)y = (-1)y × ny. Le nombre ne serait alors réel que si (-1)y = 1 ou (-1)y = -1. On a alors deux démarches pour déterminer la valeur de (-1)y :
Ainsi sur une même calculatrice (pouvant effectuer des opérations avec les nombres complexes), j'ai fait (-1)1,24 = (-1)1 × (-1)0,2 × (-1)0,04 = -1 × -1 × -1 = -1, mais en rentrant (ei × pi)1,24, qui est exactement la même chose, j'ai trouvé un nombre complexe !
En javascript et QBASIC il semble que le choix fait est le premier, on va donc laisser tomber le calcul lorsque x est négatif et que y non entier... On rajoute donc une ligne à notre script :
function puissance(x,y)
{
if(y>0)
{
if(y==Math.round(y))return (y==1?x:x*puissance(x,y-1));
else
{
if(x<0)return "Non défini !";// On a dit qu'on laissait tomber ce cas.
return decomp(x,y);// Calcul pour y non entier.
}
}
else
return (x==0?"Non défini !":(y<0?1/puissance(x,-y):1));// J'ai condensé l'écriture !
}
Maintenant que l'on a résolu le problème du x négatif, revenons en arrière et cherchons comment remédier au problème du y non entier. écrivons y de la manière suivante :
y = y' + y_1 × 10^(-1) + y_2 × 10^(-2) + ... + y_n × 10^(-n), où y' est un nombre entier et y_k le k_ième chiffre après la virgule. On aura alors :
xy = xy' × x(y_1 × 10^(-1)) × x(y_2 × 10^(-2)) × ... × x(y_n × 10^(-n))
xy = xy' × (x10^(-1))y_1 × (x10^(-2))y_2 × ... × (x10^(-n))y_n
On a déjà en main l'outil pour calculer tous nombres de la forme ab avec b est entier (à part les exceptions citées précédemment...). A partir de ça, calculons xy grâce à la manière dont on a décomposé le nombre y (au passage, on a gagné un nouveau sous-programme : la fonction decomp() qui va s'occuper de décomposer le nombre y).
Cependant dans le script la fonction racine() se sert de Math.pow() car je n'ai pas trouvé de moyen pour obtenir rapidement une racine n_ème, et la méthode que j'avais utilisée (par dichotomie) ralentissait le script... Par contre, voici pour ceux que ça intéressent la fonction decomp(X,Y) accompagné de la fonction puissance condensé (cela est possible car le grâce aux opérateurs conditionnels "? et :". Ce n'est pas très lisible mais ça économise de la place dans le code source...) :
function decomp(X,Y)
{
resultat=puissance(X,Math.floor(Y));
for(n=1;;n++)
{
puiss10=puissance(10,n);YY=Y*puiss10/10;
y_n=Math.floor((YY-Math.floor(YY))*10);
if(y_n==0)break;
resultat*=puissance(racine(X,puiss10),y_n);
}
return resultat;
}
function puissance(x,y)
{
return y>0?y==Math.round(y)?y==1?x:x*puissance(x,y-1):x<0?"Non défini !":decomp(x,y):x==0?"Non défini !":y<0?1/puissance(x,-y):1;
}