Supposons que l'IA ait une expression multiplicative avec beaucoup de multiplicands (petites expressions) où, par exemple, c est (x-1), D est (Y ** 2-16), k est (x y-60) ..... x, y sont des nombres
et je sais que c, d, k, j peut-être zéro
Est-ce que l'ordre d'écrire l'expression est-il une évaluation plus rapide?
Est-il préférable d'écrire c em> d j .... * w ou python évaluera toute expression, quelle que soit la commande que j'écris? P> p>
5 Réponses :
Probablement pas. La multiplication est l'une des opérations les moins chères de tous. Si un 0 devrait être plus rapide, il serait nécessaire de vérifier les zéros avant et c'est probablement plus lentement que de faire la multiplication. P>
La solution la plus rapide doit être multiplier.Reduce () code> p>
Vous oubliez que l'INT (Python 3.x) et Longs (Python 2.x) sont une longueur variable et la durée de multiplication augmente avec la longueur. Donc 0 * énorme * énorme code> fonctionnera beaucoup plus vite que
énorme * énorme * 0 code>
>>> import timeit >>> timeit.timeit('1*2*3*4*5*6*7*8*9*9'*6) 0.13404703140258789 >>> timeit.timeit('1*2*3*4*5*6*7*8*9*0'*6) 0.13294696807861328 >>>
N'essayez pas d'optimiser avant votre référence.
Avec cela à l'esprit, il est vrai que toutes les expressions seront évaluées même si un terme intermédiaire est zéro. P>
L'ordre peut encore importer. Les expressions sont évalué de gauche à droite . Si Si, après avoir choisi votre code avec TIMEIT ou CProfile , vous estimez que cela peut être votre situation, vous pourriez essayer de pré-évaluer puis l'heure avec Bien que Pypy soit beaucoup plus rapide, il ne semble pas optimiser cela non plus: P > a, b, c, ... code> sont des nombres très volumineux, ils pourraient forcer Python à allouer beaucoup de mémoire, ralentissant le calcul avant de ne pas atteindre
j = 0 code >. (Si
j = 0 code> est venu plus tôt dans l'expression, le produit ne serait jamais aussi important et aucune allocation de mémoire supplémentaire ne serait nécessaire). P>
C, D, K, j code> et tester p>
Timeit code> ou
CProfile code>. La seule façon de vraiment dire si cela est utile dans votre situation est de repasser. P>
% pypy-c
Python 2.7.3 (d994777be5ab, Oct 12 2013, 14:13:59)
[PyPy 2.2.0-alpha0 with GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``http://twitpic.com/52ae8f''
>>>> import timeit
>>>> timeit.timeit('10**100*10**100*0')
0.020643949508666992
>>>> timeit.timeit('0*10**100*10**100')
0.003732919692993164
Cela rend Python semble vraiment stupide. Cela ne devrait-il pas attraper des choses comme la multiplication par zéro pendant la compilation à la bytecode et les optimiser? Pypy est-il meilleur à de telles choses?
@endolith: Non, Pypy n'il optimise pas non plus. Voir au dessus.
Mais dans vos deux exemples, le temps est réduit par un ordre de grandeur lorsque vous mettez le 0 au début, non? Je suppose que j'ai manqué quelque chose .. Pouvez-vous s'il vous plaît élaborer?
@George: L'OP est demandé si Python reconnaît que 0 fois tout est 0 et est ainsi capable de court-circuiter tout le calcul et de retourner à 0. Si Python a fait cette optimisation, alors nous devrions nous attendre à 10 ** 100 * 10 ** 100 * 0 code> Pour être évalué aussi vite que
0 * 10 ** 100 * 10 ** 100 code>. Étant donné que le calendrier est clairement différent, Python ne doit pas effectuer cette optimisation.
@George: Notez que la réponse de Nick Dandoulakis montre que Python Parfois i> effectue cette optimisation, mais parfois pas. Comparez dis.dis (lambda: (256 ** 256 * 0)) code> contre
dis.dis (lambda: (100 * 256 ** 256 * 0)) code> Par exemple .
Ok, maintenant ça a du sens :) Merci pour la réponse super rapide / claire!
Python V2.6.5 ne vérifie pas les valeurs zéro.
def test1(): return 0 * 1 def test2(): a = 1 return 0 * a * 1 def test3(): return 243*(5539**35)*0 def test4(): return 0*243*(5539**35) def test5(): return (256**256)*0 def test6(): return 0*(256**256) >>> dis.dis(test1) # 0 * 1 2 0 LOAD_CONST 3 (0) 3 RETURN_VALUE >>> dis.dis(test2) # 0 * a * 1 5 0 LOAD_CONST 1 (1) 3 STORE_FAST 0 (a) 6 6 LOAD_CONST 2 (0) 9 LOAD_FAST 0 (a) 12 BINARY_MULTIPLY 13 LOAD_CONST 1 (1) 16 BINARY_MULTIPLY 17 RETURN_VALUE >>> dis.dis(test3) # 243*(5539**35)*0 9 0 LOAD_CONST 1 (243) 3 LOAD_CONST 5 (104736434394484...681759461305771899L) 6 BINARY_MULTIPLY 7 LOAD_CONST 4 (0) 10 BINARY_MULTIPLY 11 RETURN_VALUE >>> dis.dis(test4) # 0*243*(5539**35) 12 0 LOAD_CONST 5 (0) 3 LOAD_CONST 6 (104736433252667...001759461305771899L) 6 BINARY_MULTIPLY 7 RETURN_VALUE >>> dis.dis(test5) # (256**256)*0 15 0 LOAD_CONST 4 (0L) 3 RETURN_VALUE >>> dis.dis(test6) # 0*(256**256) 18 0 LOAD_CONST 1 (0) 3 LOAD_CONST 3 (323170060713110...853611059596230656L) 6 BINARY_MULTIPLY 7 RETURN_VALUE
Ceci est pour les constantes, tandis que la question implique de multiplier des expressions.
Cela implique toujours des expressions constantes, BTW. :-) Je pense que les bonnes choses à comparer seraient quelque chose comme (disons) x = 5; y = 12; (x y-58) * (x i> y-59) * (x * y-60) pour différentes commandes de l'expression finale (mais avec des constantes plus grandes).
@Shreeevatsar, allez, ne a * b * c code> démontre déjà cela? Quoi qu'il en soit, j'ai fait plus de combinaisons. Vraiment, sauf si je manque quelque chose, je ne pense pas que le compilateur incorporera un code qui vérifie les variables pour des valeurs zéro. Le code généré est toujours une série de charges, multiplie, ajoutez, soustrayez des instructions.
Désolé, aurait dû être plus clair. Je pense que vous avez déjà démontré que Python "évaluera toute expression, peu importe l'ordre que j'écris". Mais pour répondre "fait l'ordre que j'écris l'expression des questions pour une évaluation plus rapide?", Je soupçonne toujours que la réponse est oui (éventuellement pas dans la manière dont le questionneur signifiait, c'est-à-dire même si le code généré est le même), simplement parce que ( En supposant que la multiplication est effectuée de gauche à droite) Multipliez plusieurs grosses constantes de 0 devrait être plus rapide que de multiplier des constantes sans cesse croissantes, et seulement finalement par 0. Je suis trop paresseux pour ne pas tester moi-même. : p
@Shreevatsar, OK, maintenant Vous êtes clair :) Vous voulez dire 0 * 1 * 2 * 3 * N code> est plus rapide que
1 * 2 * 3 * n * 0 code>. Oui, probablement
multiplier code> ne fera pas la multiplication si un opérande est nul, le currying a zéro du début est meilleur. J'ai répondu spécifiquement à l'abandon de l'évaluation une fois que Python rencontre un zéro, mais ouais bon point ;-)
Ceci est juste un chèque rapide dans Python 3.1: et ceci en python 2.6: p> donc la commande entrave dans elle. p> J'ai aussi eu ce résultat dans Python 3.1: P> >>> timeit.timeit('(256**256)*0')
0.048995018005371094
>>> timeit.timeit('0*(256**256)')
0.1501758098602295
Nevermind ... docs.python.org/library/... < / a>
Le dernier résultat du chronométrage est due aux capacités limitées de l'optimiseur Peephole de CPPHON. Le bytecode pour l'expression (256 ** 256) * 0 code> est plié jusqu'à la constante
0 code>, de sorte que votre synchronisation n'inclut aucune opération arithmétique à tous. Pour la deuxième expression, le
256 ** 256 code> est plié à une constante, mais vous êtes toujours laissé avec la multiplication par
0 code>. Je suppose que c'est parce que le peepholer fonctionne essentiellement de gauche à droite.
Essayez Timing avec des variables non des constantes
Comment expliquer le dernier timing de Baldur?