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
34
demandé sur Wolf 2014-01-07 14:52:57

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:

timeit montre que math.pow est plus lent que ** dans tous les cas. À quoi sert math.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 ** j et convertir le résultat en un flotteur (float exponentation est automatiquement utilisé lorsque i ou j sont 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.

64
répondu poke 2014-01-07 11:25:02

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 .

3
répondu wim 2017-05-23 12:31:59

** 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.

2
répondu KDhoore 2015-05-11 10:26:19