Quelle est la manière la plus efficace donnée pour élever un entier à la puissance d'un autre entier en C?
// 2^3
pow(2,3) == 8
// 5^5
pow(5,5) == 3125
c
algorithm
math
exponentiation
Doug T.
la source
la source
int
s réels (et non à une classe énorme-int), beaucoup d'appels à ipow déborderont. Je me demande s'il existe un moyen intelligent de pré-calculer une table et de réduire toutes les combinaisons non débordantes à une simple recherche de table. Cela prendrait plus de mémoire que la plupart des réponses générales, mais serait peut-être plus efficace en termes de vitesse.pow()
pas une fonction sûreRéponses:
Exponentiation par quadrature.
Il s'agit de la méthode standard pour effectuer l'exponentiation modulaire pour des nombres énormes en cryptographie asymétrique.
la source
while (exp)
etif (exp & 1)
parwhile (exp != 0)
etif ((exp & 1) != 0)
respectivement.unsigned exp
, sinon gérerexp
correctement le négatif .n*n*n*n*n*n*n*n
utilise 7 multiplications. Cet algorithme calculem=n*n
alors, alorso=m*m
, alorsp=o*o
, oùp
= n ^ 8, avec seulement trois multiplications. Avec de grands exposants, la différence de performances est significative.Notez que l' exponentiation par quadrature n'est pas la méthode la plus optimale. C'est probablement le mieux que vous puissiez faire en tant que méthode générale qui fonctionne pour toutes les valeurs d'exposant, mais pour une valeur d'exposant spécifique, il peut y avoir une meilleure séquence qui nécessite moins de multiplications.
Par exemple, si vous voulez calculer x ^ 15, la méthode d'exponentiation par quadrature vous donnera:
C'est un total de 6 multiplications.
Il s'avère que cela peut être fait en utilisant "seulement" 5 multiplications via l' exponentiation de la chaîne d'addition .
Il n'y a pas d'algorithmes efficaces pour trouver cette séquence optimale de multiplications. De Wikipédia :
la source
Si vous devez augmenter 2 à une puissance. Le moyen le plus rapide de le faire est de décaler les bits par la puissance.
la source
2 ** 0 == 1 << 0 == 1
Voici la méthode en Java
la source
la source
pow(1, -1)
ne laisse pas la gamme d'int malgré un exposant négatif. Maintenant que l'on travaille par accident, comme çapow(-1, -1)
.Si vous voulez obtenir la valeur d'un entier pour 2 élevé à la puissance de quelque chose, il est toujours préférable d'utiliser l'option shift:
pow(2,5)
peut être remplacé par1<<5
C'est beaucoup plus efficace.
la source
power()
fonction pour travailler uniquement avec des nombres entiersComplexité = O (log (exp))
power()
fonction pour fonctionner avec une base exp et négative flottante .Complexité = O (log (exp))
la source
float
dans le deuxième bloc de code présenté (pensez à montrer commentpower(2.0, -3)
est calculé).negative exp and float base
solution? pourquoi nous utilisons temp, séparons exp par 2 et vérifions exp (pair / impair)? Merci!Un cas extrêmement spécialisé est, lorsque vous avez besoin de dire 2 ^ (- x au y), où x, bien sûr, est négatif et y est trop grand pour faire un décalage sur un int. Vous pouvez toujours faire 2 ^ x en temps constant en vissant avec un flotteur.
Vous pouvez obtenir plus de pouvoirs de 2 en utilisant un double comme type de base. (Merci beaucoup aux commentateurs d'avoir aidé à corriger ce message).
Il y a aussi la possibilité que d'en savoir plus sur les flotteurs IEEE , d'autres cas spéciaux d'exponentiation pourraient se présenter.
la source
Tout comme un suivi des commentaires sur l'efficacité de l'exponentiation par quadrature.
L'avantage de cette approche est qu'elle s'exécute en temps log (n). Par exemple, si vous deviez calculer quelque chose d'énorme, tel que x ^ 1048575 (2 ^ 20 - 1), vous n'avez qu'à parcourir la boucle 20 fois, pas 1 million + en utilisant l'approche naïve.
De plus, en termes de complexité du code, c'est plus simple que d'essayer de trouver la séquence de multiplications la plus optimale, comme le suggère la Pramod.
Éditer:
Je suppose que je devrais clarifier avant que quelqu'un m'étiquette pour le potentiel de débordement. Cette approche suppose que vous avez une sorte de bibliothèque de type énorme.
la source
Tard à la fête:
Vous trouverez ci-dessous une solution qui traite également du
y < 0
mieux qu'elle peut.intmax_t
pour une portée maximale. Il n'y a aucune disposition pour les réponses qui ne correspondent pasintmax_t
.powjii(0, 0) --> 1
ce qui est un résultat courant pour ce cas.pow(0,negative)
, un autre résultat indéfini, renvoieINTMAX_MAX
Ce code utilise une boucle
for(;;)
pour toujours pour éviter lebase *= base
commun final dans d'autres solutions en boucle. Cette multiplication est 1) non nécessaire et 2) pourrait être unint*int
débordement qui est UB.la source
powjii(INT_MAX, 63)
provoque UBbase *= base
. Pensez à vérifier que vous pouvez multiplier ou passer à non signé et laissez-le boucler.exp
signé. Cela complique le code en raison de la situation étrange où(-1) ** (-N)
est valide, et toutabs(base) > 1
sera0
pour des valeurs négatives deexp
, il est donc préférable de le faire non signé et d'enregistrer ce code.y
tel que signé n'est pas vraiment nécessaire et apporte les complications que vous avez commentées, mais la demande de OP était spécifiquepow(int, int)
. Ces bons commentaires appartiennent donc à la question du PO. Comme OP n'a pas spécifié quoi faire en cas de débordement, une mauvaise réponse bien définie n'est que légèrement meilleure que UB. Étant donné "le moyen le plus efficace", je doute qu'OP se soucie de OF.solution plus générique considérant exponenet négatif
la source
pow(i, INT_MIN)
pourrait être une boucle infinie.pow(i, INT_MIN)
n'est pas un débordement d'entier. L'affectation de ce résultat àtemp
peut certainement déborder, ce qui pourrait entraîner la fin des temps , mais je me contenterai d'une valeur apparemment aléatoire. :-)Une autre implémentation (en Java). Peut ne pas être la solution la plus efficace mais le nombre d'itérations est le même que celui de la solution exponentielle.
la source
J'utilise récursif, si l'exp est pair, 5 ^ 10 = 25 ^ 5.
la source
En plus de la réponse d'Elias, qui provoque un comportement indéfini lorsqu'il est implémenté avec des entiers signés et des valeurs incorrectes pour une entrée élevée lorsqu'il est implémenté avec des entiers non signés,
voici une version modifiée de l'exponentiation par quadrature qui fonctionne également avec les types entiers signés et ne donne pas de valeurs incorrectes:
Considérations pour cette fonction:
En cas de débordement ou d'emballage,
return 0;
J'ai utilisé
int64_t
, mais n'importe quelle largeur (signée ou non signée) peut être utilisée avec peu de modifications. Cependant, si vous devez utiliser un type entier à largeur non fixe, vous devrez changerSQRT_INT64_MAX
par(int)sqrt(INT_MAX)
(dans le cas de l'utilisationint
) ou quelque chose de similaire, qui devrait être optimisé, mais il est plus laid et non une expression constante C. Le fait de convertir le résultat desqrt()
en unint
n'est pas très bon à cause de la précision en virgule flottante dans le cas d'un carré parfait, mais comme je ne connais aucune implémentation oùINT_MAX
-ou le maximum de tout type- est un carré parfait, vous pouvez vivre avec ça.la source
J'ai implémenté un algorithme qui mémorise toutes les puissances calculées et les utilise ensuite en cas de besoin. Ainsi, par exemple, x ^ 13 est égal à (x ^ 2) ^ 2 ^ 2 * x ^ 2 ^ 2 * x où x ^ 2 ^ 2 il a été extrait du tableau au lieu de le calculer à nouveau. Il s'agit essentiellement de l'implémentation de la réponse @Pramod (mais en C #). Le nombre de multiplication nécessaire est Ceil (Log n)
la source
public
? 2 fonctions nommées de la même façon? Ceci est une question C.Mon cas est un peu différent, j'essaie de créer un masque à partir d'une puissance, mais j'ai pensé partager la solution que j'ai trouvée de toute façon.
Évidemment, cela ne fonctionne que pour des puissances de 2.
la source
#define MASK(e) (((e) >= 64) ? -1 :( (1 << (e)) - 1))
ça, donc qui peuvent être calculés au moment de la compilationSi vous connaissez l'exposant (et il s'agit d'un entier) au moment de la compilation, vous pouvez utiliser des modèles pour dérouler la boucle. Cela peut être rendu plus efficace, mais je voulais démontrer le principe de base ici:
Nous terminons la récursivité en utilisant une spécialisation de modèle:
L'exposant doit être connu au moment de l'exécution,
la source
(c != c++) == 1