64 votes

Le décalage des bits est-il plus rapide que la multiplication et la division en Java ? .NET ?

Le décalage des bits à gauche et à droite est apparemment plus rapide que les opérations de multiplication et de division sur la plupart (tous ?) des CPU s'il se trouve que vous utilisez une puissance de 2. Cependant, il peut réduire la clarté du code pour certains lecteurs et certains algorithmes. Le décalage des bits est-il vraiment nécessaire pour les performances, ou puis-je espérer que le compilateur/VM remarque le cas et l'optimise (en particulier, lorsque la puissance de 2 est un littéral) ? Je suis principalement intéressé par le comportement de Java et de .NET, mais je serais heureux de recevoir des informations sur les implémentations d'autres langages.

88voto

Michael Burr Points 181287

La plupart des compilateurs actuels ne se contentent pas de convertir la multiplication ou la division par une puissance de deux en opérations de décalage. Souvent, un multiplicateur ou un diviseur peut être décomposé en une série de décalages et d'additions, et si cette série d'opérations est plus rapide que le multiplicateur ou le diviseur, le compilateur l'utilisera.

Pour la division par une constante, le compilateur peut souvent convertir l'opération en une multiplication par un "nombre magique" suivi d'un décalage. Cela peut représenter un gain de temps considérable, car la multiplication est souvent beaucoup plus rapide qu'une opération de division.

Le livre d'Henry Warren, Hacker's Delight, contient une mine d'informations sur ce sujet, qui est également très bien couvert sur le site web d'accompagnement :

Voir également une discussion (avec un lien ou deux) ici :

Quoi qu'il en soit, tout cela revient à permettre au compilateur de s'occuper des détails fastidieux des micro-optimisations. Cela fait des années que l'on n'a pas fait ses propres modifications sans tenir compte du compilateur.

87voto

Jason Creighton Points 7080

Presque tout environnement digne de ce nom optimisera cette tâche pour vous. Et s'il ne le fait pas, vous avez d'autres chats à fouetter. Sérieusement, ne perdez pas une seconde de plus à y penser. Vous saurez quand vous aurez des problèmes de performance. Et après avoir lancé un profileur, vous saurez ce qui en est la cause, et il devrait être assez clair comment le corriger.

Vous n'entendrez jamais quelqu'un dire "mon application était trop lente, puis j'ai commencé à remplacer au hasard". x * 2 avec x << 1 et tout était réparé !" Les problèmes de performance sont généralement résolus en trouvant un moyen de faire un ordre de grandeur de moins de travail, et non en trouvant un moyen de faire le même travail 1% plus vite.

33voto

Bill Crim Points 412

Les humains ont tort dans ces cas-là.

99% quand ils essaient de deviner un compilateur moderne (et tous les compilateurs futurs).
99,9% quand ils essaient de deviner les JIT modernes (et tous les futurs) en même temps.
99,999 % quand ils essaient de deviner les optimisations modernes (et futures) des processeurs.

Programmez d'une manière qui décrit précisément ce que vous voulez accomplir, et non comment le faire. Les futures versions du JIT, de la VM, du compilateur et du CPU peuvent toutes être améliorées et optimisées de manière indépendante. Si vous spécifiez quelque chose d'aussi minuscule et spécifique, vous perdez le bénéfice de toutes les optimisations futures.

20voto

Greg Hewgill Points 356191

Vous pouvez presque certainement compter sur l'optimisation de la multiplication en puissance de deux pour une opération de décalage. C'est l'une des premières optimisations que les étudiants en construction de compilateurs apprendront :)

Cependant, je ne pense pas qu'il y ait de garantie à cet égard. Votre code source devrait refléter votre intention plutôt que d'essayer de dire à l'optimiseur ce qu'il doit faire. Si vous voulez augmenter une quantité, utilisez la multiplication. Si vous déplacez un champ de bits d'un endroit à un autre (pensez à la manipulation des couleurs RVB), utilisez une opération de décalage. Dans tous les cas, votre code source reflétera ce que vous faites réellement.

12voto

izb Points 12736

Notez que le décalage vers le bas et la division donneront (en Java, certainement) des résultats différents pour les nombres négatifs et impairs.

int a = -7;
System.out.println("Shift: "+(a >> 1));
System.out.println("Div:   "+(a / 2));

Imprimés :

Shift: -4
Div:   -3

Comme Java n'a pas de nombres non signés, il n'est pas vraiment possible pour un compilateur Java d'optimiser cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X