Lequel est le plus efficace en utilisant math.pow ou l'opérateur **? Quand devrais-je utiliser l'un sur l'autre?
Jusqu'à présent, je sais que x**y
peut renvoyer un int
ou un float
si vous utilisez une décimale, la fonction pow
renverra un flottant
import math
print math.pow(10, 2)
print 10. ** 2
L'utilisation de l'opérateur motorisé **
Sera plus rapide car il n'aura pas la surcharge d'un appel de fonction. Vous pouvez le voir si vous démontez 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 car 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 lors du chronométrage:
>>> 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
Ainsi, alors que pow
et math.pow
Sont environ deux fois plus lents, ils sont encore assez rapides pour ne pas s'en soucier. À moins que vous ne puissiez réellement identifier l'exponentiation comme un goulot d'étranglement, il n'y aura aucune raison de choisir une méthode plutôt qu'une autre si la clarté diminue. Cela s'applique particulièrement puisque pow
offre une opération modulo intégrée par exemple.
Alfe a posé une bonne question dans les commentaires ci-dessus:
timeit
montre quemath.pow
Est plus lent que**
Dans tous les cas. À quoi sertmath.pow()
de toute façon? Quelqu'un a-t-il une idée où cela peut être avantageux alors?
La grande différence de math.pow
À la fois avec pow
et l'opérateur de puissance **
Est qu'il toujours utilise la sémantique flottante. Donc, si pour une raison quelconque, vous voulez vous assurer de récupérer un flottant, alors math.pow
Assurera cette propriété.
Prenons un exemple: nous avons deux nombres, i
et j
, et nous n'avons aucune idée s'ils sont des flottants ou des entiers. Mais nous voulons avoir un résultat flottant de i^j
. Alors, quelles options avons-nous?
i ** j
.i ** j
Et convertir le résultat en un flottant (l'exposant de flottement est automatiquement utilisé lorsque i
ou j
sont des flottants, donc le résultat est le même).math.pow
.Alors 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 réfléchissez, la surcharge de l'appel de fonction a également disparu maintenant, car dans toutes les autres alternatives, nous devons appeler float()
.
De plus, il peut être utile de noter que le comportement de **
Et pow
peut être remplacé en implémentant la méthode spéciale __pow__
(Et __rpow__
) Pour types personnalisés. Donc, si vous ne le souhaitez pas (pour quelque raison que ce soit), utiliser math.pow
Ne le fera pas.
Juste pour le protocole: l'opérateur **
Appelle la fonction 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 à partir des pouvoirs, 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)
Lorsque j'ai exécuté cela, j'ai obtenu 0.0
Dans le premier cas, ce qui ne peut évidemment pas être vrai, car 13 est impair (et donc tous ses pouvoirs intégraux). La version math.pow
Utilise une précision limitée qui provoque une erreur.
Par souci d'équité, nous devons dire que 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 j'obtiens en sortie:
0.240936803195
1.4775809183
Quelques exemples en ligne
math.pow
)pow
sur les valeurs int)pow
sur les valeurs flottantes)Eh bien, ils sont pour différentes tâches, vraiment.
Utilisez pow
(équivalent à x ** y
avec deux arguments) lorsque vous voulez une arithmétique entière.
Et utilise math.pow
si l'un des arguments est float et que vous voulez une sortie float.
Pour une discussion sur les différences entre pow
et math.pow
, voyez ceci 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 alors
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.