2010-10-26 4 views
2

Deux parties deux ma question. Ce qui est plus efficace/plus rapide:longues lignes d'arithmétique entière

int a,b,c,d,e,f; 
int a1,b1,c1,d1,e1,f1; 
int SumValue=0; // oops forgot zero 
// ... define all values 
SumValue=a*a1+b*b1+c*c1+d*d1+e*e1*f*f1; 

ou

Sumvalue+=a*a1+b*b1+c*c1; 
Sumvalue+=d*d1+e*e1*f*f1; 

Je suppose que le premier est. Ma deuxième question est pourquoi.

Je suppose qu'une troisième question est, à tout moment serait-il nécessaire de rompre une opération d'addition (outre les limitations du compilateur sur le nombre de suites de lignes etc ...).

Modifier

est la seule fois que je voyais un ralentissement quand alors l'opération arithmétique entière ne pouvait pas tenir dans le cache? Je pense que c'est impossible - le compilateur devient probablement fou de deux continuations de lignes avant que cela puisse arriver. Peut-être que je devrai jouer demain et voir.

+0

Son arithmétique, avec un 'e' :-) – Arun

+1

Mettez-les dans une très grande boucle, et chronométrer les. Ensuite, vous saurez lequel est le plus rapide. – abelenky

+0

@ArunSaha, pourquoi commenter quand vous pouvez éditer? :-) – ergosys

Répondre

5

Avez-vous mesuré cela? Le code machine optimisé pour les deux approches sera probablement très similaire, sinon identique.

EDIT: Je viens testé, les résultats sont ce que je pensais:

$ gcc -O2 -S math1.c # your first approach 
$ gcc -O2 -S math2.c # your second approach 
$ diff -u math1.s math2.s 

--- math1.s 2010-10-26 19:35:06.487021094 +0200 
+++ math2.s 2010-10-26 19:35:08.918020954 +0200 
@@ -1,4 +1,4 @@ 
- .file "math1.c" 
+ .file "math2.c" 
    .section .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
    .string "%d\n" 

Voilà. Code machine identique.

+2

Oui, mais le code machine que vous avez généré n'effectue probablement même pas l'arithmétique, du moins si vous avez copié-collé l'extrait à partir de l'OP. Si vous utilisez des indicateurs d'optimisation, cela optimisera probablement l'arithmétique, puisque vous ne faites rien avec 'SumValue'. Quand je regarde l'assembly généré par gcc, il ne fait même pas l'arithmétique si je mets des drapeaux d'optimisation. La seule chose dans la section '.main' est une instruction' ret'. –

+0

merci - devrait avoir diff'd moi-même je ne pensais pas:) – Marm0t

+0

@Charles, je me suis assuré que SumValue a été utilisé en le passant à 'printf ("% d \ n ")' et les résultats sont les mêmes . –

0

Il est fort probable qu'ils soient convertis en autant d'instructions machine, ce qui leur prendrait le même temps.

1

C'est pourquoi il est utile de se familiariser avec le langage d'assemblage. Dans les deux cas, des instructions d'assemblage seront générées pour charger des paires d'opérandes dans des registres et effectuer une addition/multiplication, et stocker le résultat dans un registre. Des instructions pour stocker le résultat final dans l'adresse mémoire représentée par SumValue peuvent également être générées, en fonction de la façon dont vous utilisez SumValue.

En résumé, les deux constructions sont susceptibles de fonctionner de la même manière, notamment avec les indicateurs d'optimisation. Et même si ne font pas effectuer la même chose sur une plate-forme, il n'y a rien d'intrinsèque à l'une ou l'autre approche qui pourrait vraiment aider à expliquer pourquoi au niveau C++. Au mieux, vous seriez en mesure de comprendre la raison pour laquelle l'un fonctionne mieux que l'autre en regardant comment votre compilateur traduit les constructions C++ en instructions d'assemblage.

je suppose une troisième question est, à tout moment serait-il nécessaire de briser en place une opération d'addition (en plus limitations du compilateur nombre de ligne continuations etc ...).

Ce n'est pas vraiment nécessaire pour interrompre une opération d'addition. Mais cela pourrait aider à la lisibilité.

2

Il n'y a pas de limite arbitraire au nombre d'opérations que vous pouvez combiner sur une ligne ... pratiquement, le compilateur acceptera n'importe quel nombre que vous voudrez lui lancer. La prise en compte des opérations par les compilateurs se produit longtemps après que les nouvelles lignes sont incrustées - il s'agit de symboles lexicaux et de règles de grammaire, puis d'un arbre de syntaxe abstraite, d'ici là. À moins que votre compilateur ne soit très mal écrit, les deux instructions fonctionneront aussi bien pour les données int.Notez que dans le résultat = a * b + c * d + e * f etc., le compilateur n'a pas de points de séquence et connaît la précédence, donc a une liberté totale pour évaluer et combiner les sous-expressions en parallèle (matériel adapté) . Avec un résultat + = a * b; résultat + = c * d; approche, vous insérez des points de séquence de sorte que le compilateur est invité à compléter une expression avant l'autre, mais est libre de réaliser que le résultat n'est pas utilisé ailleurs entre incréments, donc il est libre d'optimiser comme dans le premier cas . Plus généralement: le meilleur conseil que je peux donner pour de telles requêtes de performance est 1) ne vous inquiétez pas que ce soit un problème pratique à moins que votre programme fonctionne trop lentement, puis profil pour savoir où 2) si curieux ou profilage indique un problème, puis essayez les deux/toutes les approches que vous pouvez penser et mesurer les performances réelles.

A côté: + = peut être plus efficace parfois, par ex. pour concaténer à une chaîne existante, comme + sur ces objets peut impliquer la création de provisoires et plus d'allocation de mémoire - les expressions de modèle contourner ce problème mais sont rarement utilisées car elles sont très complexes à implémenter et plus lentes à compiler.

+0

+1 pour ne pas s'inquiéter à ce sujet et profiler votre programme – rve

Questions connexes