Fortran (conçu pour le calcul scientifique) possède un opérateur de puissance intégré et, pour autant que je sache, les compilateurs Fortran optimisent généralement l'élévation à la puissance des entiers d'une manière similaire à celle que vous décrivez. Malheureusement, le C/C++ ne dispose pas d'opérateur de puissance, mais seulement de la fonction de bibliothèque pow()
. Cela n'empêche pas des compilateurs intelligents de traiter pow
spécialement et le calculer de manière plus rapide pour des cas particuliers, mais il semble qu'ils le fassent moins souvent ...
Il y a quelques années, j'ai essayé de rendre plus pratique le calcul des puissances d'entiers de manière optimale, et j'ai trouvé ce qui suit. C'est du C++, pas du C cependant, et cela dépend toujours de l'intelligence du compilateur quant à l'optimisation/inline des choses. Quoi qu'il en soit, j'espère que vous le trouverez utile dans la pratique :
template<unsigned N> struct power_impl;
template<unsigned N> struct power_impl {
template<typename T>
static T calc(const T &x) {
if (N%2 == 0)
return power_impl<N/2>::calc(x*x);
else if (N%3 == 0)
return power_impl<N/3>::calc(x*x*x);
return power_impl<N-1>::calc(x)*x;
}
};
template<> struct power_impl<0> {
template<typename T>
static T calc(const T &) { return 1; }
};
template<unsigned N, typename T>
inline T power(const T &x) {
return power_impl<N>::calc(x);
}
<strong>Clarification pour les curieux : </strong>cela ne permet pas de trouver la manière optimale de calculer les puissances, mais puisque <a href="http://en.wikipedia.org/wiki/Addition-chain_exponentiation">trouver la solution optimale est un problème NP-complet </a>et cela ne vaut la peine d'être fait que pour les petites puissances de toute façon (contrairement à l'utilisation des <code>pow</code> ), il n'y a aucune raison de s'attarder sur les détails.
Ensuite, il suffit de l'utiliser comme power<6>(a)
.
Cela permet de taper facilement les pouvoirs (pas besoin d'épeler 6 a
avec des parenthèses), et vous permet d'avoir ce type d'optimisation sans -ffast-math
au cas où vous auriez quelque chose qui dépende de la précision, comme sommation compensée (un exemple où l'ordre des opérations est essentiel).
Vous pouvez probablement aussi oublier qu'il s'agit de C++ et l'utiliser simplement dans le programme C (s'il se compile avec un compilateur C++).
J'espère que cela pourra vous être utile.
EDITAR:
Voici ce que j'obtiens de mon compilateur :
Para a*a*a*a*a*a
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
Para (a*a*a)*(a*a*a)
,
movapd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm0, %xmm0
Para power<6>(a)
,
mulsd %xmm0, %xmm0
movapd %xmm0, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm0, %xmm1
16 votes
Que signifie "reconnaître pow(a,6)" ?
1 votes
Je suis surpris
gcc
fait no optimiser cela. Le compilateur FORTRAN des années 1970 que j'ai utilisé sur CDC Cyber faisait ce genre de transformation, même sans sélectionner d'optimisation. Je pense que la V6 d'Unix (c. 1978)C
le compilateur le faisait lorsque l'optimisation était activée, bien que la plupart des optimisations qu'il effectuait visaient à économiser de l'espace dans le code, une denrée précieuse à l'époque.707 votes
Um... vous savez qu'un a a a a a et (a a a)*(a a*a) ne sont pas les mêmes avec les nombres à virgule flottante, n'est-ce pas ? Vous devrez utiliser -funsafe-math ou -ffast-math ou autre pour cela.
132 votes
Je vous suggère de lire "What Every Computer Scientist Should Know About Floating Point Arithmetic" de David Goldberg : download.oracle.com/docs/cd/E19957-01/806-3568/… après quoi vous aurez une compréhension plus complète de la fosse de goudron dans laquelle vous venez de pénétrer !
210 votes
Une question parfaitement raisonnable. Il y a 20 ans, j'ai posé la même question générale et, en éliminant ce seul goulot d'étranglement, j'ai réduit le temps d'exécution d'une simulation de Monte-Carlo de 21 heures à 7 heures. Le code de la boucle interne a été exécuté 13 trillions de fois au cours du processus, mais il a permis de faire entrer la simulation dans une fenêtre de nuit. (voir réponse ci-dessous)
33 votes
Peut-être jeter
(a*a)*(a*a)*(a*a)
dans le mélange, aussi. Même nombre de multiplications, mais probablement plus précis.12 votes
Tout d'abord, la manière dont cette optimisation est réalisée dépend grandement du type de
a
a...2 votes
Plug sans vergogne : en plus de l'article de Goldberg, je vous suggère de lire le mien, hal.archives-ouvertes.fr/file/index/docid/281429/filename/
1 votes
@Rok En fait, un bon optimiseur pourrait aller encore plus loin. a*a ne doit être fait qu'une fois. Ce résultat pourrait être réutilisé assez facilement pour le réduire à seulement 3 opérations de multiplication.
4 votes
@penguin359 : Oui, 3, exactement la même chose que
(a*a*a)*(a*a*a)
C'est ce que j'ai suggéré comme alternative. Qu'est-ce que vous essayez de dire ?