Les exponentielles en python x.**y vs mathématiques.pow(x, y)
qui est plus efficace en mathématiques.pow Ou l'opérateur**? Quand dois-je utiliser l'un plutôt que l'autre?
Jusqu'à présent je sais que x**y peut retourner un int ou un float si vous utilisez une décimale
la fonction pow retournera un flotteur
import math
print math.pow(10, 2)
print 10. ** 2
4 réponses
utilisant l'opérateur de puissance ** sera plus rapide car il n'aura pas le plafond d'un appel de fonction. Vous pouvez le voir si vous désassemblez le code Python:
>>> dis.dis('7. ** i')
1 0 LOAD_CONST 0 (7.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
>>> dis.dis('pow(7., i)')
1 0 LOAD_NAME 0 (pow)
3 LOAD_CONST 0 (7.0)
6 LOAD_NAME 1 (i)
9 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
12 RETURN_VALUE
>>> dis.dis('math.pow(7, i)')
1 0 LOAD_NAME 0 (math)
3 LOAD_ATTR 1 (pow)
6 LOAD_CONST 0 (7)
9 LOAD_NAME 2 (i)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 RETURN_VALUE
notez que j'utilise une variable i comme exposant ici parce que des expressions constantes comme 7. ** 5 sont en fait évaluées au moment de la compilation.
maintenant, dans la pratique, cette différence n'a pas beaucoup d'importance, comme vous pouvez le voir en chronométrant:
>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255
donc, alors que pow et math.pow sont environ deux fois plus lents, ils sont encore assez rapide pour ne pas s'en soucier beaucoup. À moins que vous ne puissiez réellement identifier l'exponentiation comme un goulot d'étranglement, il n'y aura pas de raison de choisir une méthode plutôt que l'autre si la clarté diminue. Cela s'applique particulièrement puisque pow offre une opération de modulo intégrée par exemple.
Alfe a demandé une bonne question dans les commentaires ci-dessus:
timeitmontre quemath.powest plus lent que**dans tous les cas. À quoi sertmath.pow()de toute façon? Personne n'a une idée d'où il peut être de n'importe quel avantage?
la grande différence de math.pow à la fois le bâti pow et l'opérateur de puissance ** est qu'il toujours utilise la sémantique de flotteur. Donc, si vous, pour une raison quelconque, voulez vous assurer que vous obtenez un flottant comme un résultat de retour, puis math.pow assurera cette propriété.
pensons à un exemple: nous avons deux nombres, i et j , et n'avons aucune idée si ce sont des flotteurs ou des entiers. Mais nous voulons un float résultat de i^j . Alors, quelles options avons-nous?
- nous pouvons convertir au moins un des arguments en un float et ensuite faire
i ** j. - nous pouvons faire
i ** jet convertir le résultat en un flotteur (float exponentation est automatiquement utilisé lorsqueioujsont des flotteurs, de sorte que le résultat est le même). - on peut utiliser
math.pow.
donc, testons ceci:
>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439
comme vous pouvez le voir, math.pow est en fait plus rapide! Et si vous y pensez, le overhead de l'appel de fonction est aussi parti maintenant, parce que dans toutes les autres alternatives, nous devons appeler float() .
en outre, il pourrait être intéressant de noter que le comportement de ** et pow peut être dépassé en mettant en œuvre la méthode spéciale __pow__ (et __rpow__ ) pour les types personnalisés. Donc, si vous ne le voulez pas (pour une raison quelconque), utiliser math.pow ne le fera pas.
juste pour le protocole: l'opérateur ** appelle la fonction pow intégrée" qui accepte un troisième argument optionnel (module) si les deux premiers arguments sont des types entiers.
donc, si vous avez l'intention de calculer les restes des puissances, utilisez la fonction intégrée. Le math.pow peut vous donner de faux résultats:
import math
base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)
quand j'ai couru ceci, j'ai eu 0.0 dans le premier cas qui évidemment ne peut pas être vrai, parce que 13 est étrange (et donc tous ses pouvoirs intégraux). La version math.pow utilise une précision limitée qui provoque une erreur.
pour des raisons d'équité, nous devons dire, math.pow peut être beaucoup plus rapide:
import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("pow(2, 100)")
voici ce que je reçois en sortie:
0.240936803195
1.4775809183
quelques exemples en ligne
- http://ideone.com/qaDWRd (reste erroné avec
math.pow) - http://ideone.com/g7J9Un (performances inférieures avec
powsur les valeurs int) - http://ideone.com/KnEtXj (performances légèrement inférieures avec
powsur les valeurs des flotteurs)
Eh bien, ils sont pour différentes tâches, vraiment.
utiliser pow (équivalent à x ** y avec deux arguments) lorsque vous voulez arithmétique entière.
et utilisez math.pow si l'un ou l'autre des arguments est float, et vous voulez la sortie float.
pour une discussion sur les différences entre pow et math.pow , voir cette question .
** est en effet plus rapide que math.pow() , mais si vous voulez une fonction quadratique simple comme dans votre exemple, il est encore plus rapide d'utiliser un produit.
10.*10.
sera plus rapide que
10.**2
la différence n'est pas grande et n'est pas perceptible avec une seule opération (en utilisant timeit ), mais avec un grand nombre d'opérations, elle peut être significative.