Est la multiplication et la division à l'aide d'opérateurs de décalage dans C vraiment le plus rapide?
De Multiplication et de division peut être réalisé en utilisant des bits les opérateurs, par exemple
i*2 = i<<1
i*3 = (i<<1) + i;
i*10 = (i<<3) + (i<<1)
et ainsi de suite.
Est-il réellement plus rapide d'utiliser le dire (i<<3)+(i<<1)
à multiplier par 10 que l'utilisation de i*10
directement? Est-il une sorte d'entrée qui ne peut pas être multiplié ou divisé de cette manière?
- En fait, bon marché division par une constante d'autre qu'une puissance de deux est possible, mais difficile de sujet auquel vous n'êtes pas de faire la justice avec "/Division ... /divisé" dans votre question. Voir par exemple hackersdelight.org/divcMore.pdf (ou obtenir le livre "Hacker s delight" si vous le pouvez).
- Ça sonne comme quelque chose qui pourrait facilement être testé.
- Comme d'habitude, ça dépend. Une fois, j'ai essayé ce en assembleur sur un processeur Intel 8088 (IBM PC/XT) où une multiplication pris un bazillion horloges. Changements et ajoute exécuté beaucoup plus rapide, de sorte qu'il semblait être une bonne idée. Cependant, tout en multipliant l'unité de bus est libre de remplir l'instruction de la file d'attente et la prochaine instruction a pu alors commencer immédiatement. Après une série de changements et ajoute l'instruction file d'attente est vide et le CPU aurait à attendre la prochaine instruction à être récupérées à partir de la mémoire (un octet à la fois!). Mesurez, mesurez, mesurez!
- il était donc plus de difficultés à la mise en œuvre de la nouvelle version alors il valait la peine ou vous êtes-vous l'utiliser?
- Aussi, méfiez-vous que le droit-le déplacement est uniquement définie pour les entiers non signés. Si vous avez un entier signé, il n'est pas défini si 0 ou le bit le plus élevé sont complétées à partir de la gauche. (Et n'oubliez pas le temps qu'il faut pour quelqu'un d'autre (même vous) pour lire le code d'un an plus tard!)
- Non, j'ai fini à l'aide de la multiplier, parce que c'était la manière la plus rapide pour l'ensemble de la routine. Le 8088 a été limitée par le bus 8 bits, de sorte que la taille du code est souvent plus important que le nombre d'horloges pour chaque instruction.
- En fait, un bon compilateur optimisant la volonté de mettre en œuvre la multiplication et de la division avec les changements quand ils sont plus rapides.
- G. Dans le [s|b]ad vieux jours avant une bonne optimisation des compilateurs et des processeurs rapides, j'ai utilisé mon propre "10 fois" de routine (maj une fois & enregistrer, puis sur maj deux fois plus et ajouter à la valeur enregistrée). Aujourd'hui, il ne vaut pas la peine de déranger, mais à l'époque, il fait la différence entre les utilisateurs d'obtenir un rapport immédiatement, ou aller pour une pause café pendant qu'ils attendaient.
- Il convient de mentionner que l'optimisation est appelée réduction de la résistance.
- Il n'y a pas une telle chose comme "mieux". Sur un 8 broches du microcontrôleur, vous pouvez optimiser pour moins d'instructions. Si le processeur est un vecteur de processeur que vous craignent peut-être que vous pouvez faire 16 multiplications dans l'enseignement et la nécessité d'incorporer votre algorithme sur un grand vecteur de moteur. Comme tout le monde le dit, de rendre votre code dire quoi faire, pas comment le faire. Si vous connaissez un code spécifique chemin prend 90% de votre temps CPU, puis le bas niveau de stuff SI les mesures dire que ça aide. Autre chose serait une perte de temps qui pourrait être consacré en fait de l'optimisation de choses.
- Je ne suis pas sûr que j'ai jamais vu un compilateur où divisant signé un nombre par une puissance de 2 n'a pas été plus lent que de faire une maj de droite. On pourrait dire que si les dividendes ne seront jamais négatifs que l'on jette de la non signé et de faire la division, mais qui peuvent causer des bizarreries de son propre.
- Je suis un peu en retard à cette discussion, mais un récent test de la curiosité a montré que int64 division était d'environ 8 fois plus lent que bitshifting mais int64 de multiplication a été le même. Il est intéressant de noter, int32 division produit les mêmes résultats que int32 bitshifting. J'ai couru ce test très impromptu en mode de débogage, de sorte que ces résultats pourraient ne pas être représentatifs de l'objet dans l'application.
Vous devez vous connecter pour publier un commentaire.
Réponse courte: Pas probable.
Réponse longue:
Votre compilateur a un optimiseur qui sait se multiplient aussi vite que votre cible de l'architecture du processeur est capable. Votre meilleur pari est de dire au compilateur de votre intention clairement (c'est à dire i*2 plutôt que i << 1) et le laisser décider de ce que la manière la plus rapide de montage/code machine de la séquence. Il est même possible que le processeur lui-même a mis en œuvre les multiplier instruction comme une séquence de changements & ajoute dans microcode.
Ligne de fond-ne pas passer beaucoup de temps à se préoccuper de cela. Si vous voulez dire à la maj, maj. Si vous voulez dire à se multiplier, à se multiplier. Faire ce qui est sémantiquement plus clair--vos collègues vous en seront reconnaissantes. Ou, plus probablement, vous maudissent, plus tard, si vous faites le contraire.
gcc -O3
sur x86 avecreturn i*10
que depuis le changement de version. Comme quelqu'un qui a l'air à la sortie du compilateur beaucoup (voir plusieurs de mes asm / optimisation des réponses), je ne suis pas surpris. Il y a des moments où il peut aider à main-tenir le compilateur sur une façon de faire les choses, mais ce n'est pas l'un d'eux. gcc est bon en math entier, parce que c'est important.millis() >> 2
; il Aurait été trop demander à juste diviser?Juste un béton de point de mesure: il y a plusieurs années, j'ai comparé les deux
versions de mon algorithme de hachage:
et
Sur chaque machine je comparés sur, le premier a été au moins aussi vite que
la deuxième. Curieusement, il est parfois plus rapide (par exemple sur un
Sun Sparc). Lorsque le matériel ne prend pas en charge rapide de multiplication (et
la plupart n'avait pas à l'époque), le compilateur serait de convertir la multiplication
dans les combinaisons appropriées de changements et add/sub. Et parce qu'il
savait l'objectif final, il peut parfois le faire en moins d'instructions que
lorsque vous avez explicitement écrit, les modifications et l'ajout/subs.
Noter que c'était quelque chose comme il y a 15 ans. Heureusement, les compilateurs
ont ne cesse de s'améliorer depuis, alors vous pouvez très bien compter sur l'
compilateur de faire la bonne chose, probablement mieux que vous pourrait. (Aussi,
la raison pour laquelle le code a l'air tellement C new'ish est parce qu'il a plus de 15 ans.
J'avais évidemment utiliser
std::string
et itérateurs d'aujourd'hui).En plus de toutes les autres bonnes réponses ici, permettez-moi de souligner une autre raison de ne pas utiliser la touche maj enfoncée lorsque vous signifie diviser ou multiplier. Je n'ai jamais vu une fois à quelqu'un de présenter un bug par l'oubli de la priorité relative de multiplication et d'addition. J'ai vu les bugs introduits lors de l'entretien les programmeurs ont oublié que le "multiplier" via une maj est logiquement une multiplication, mais pas syntaxiquement de la même priorité que la multiplication.
x * 2 + z
etx << 1 + z
sont très différents!Si vous travaillez sur numéros de puis utiliser des opérateurs arithmétiques comme
+ - * /%
. Si vous travaillez sur des tableaux de bits, utilisez peu tourner les opérateurs comme& ^ | >>
. Ne pas les mélanger; une expression qui est à la fois peu tripoter et de l'arithmétique est un bug en attente de se produire.(X+128)>>8
est rapide et assez clair par rapport à tout ce que je peux la figure à l'aide de l'opérateur"/". Connaissez-vous des formulations à l'aide de "/", qui ne sont pas deux rend la lecture plus difficile et plus lent à s'exécuter?x >= 0 ? (x + 128)/256 : (x-127)/256
semble laid, même si elle a fonctionné aussi bien que(x+128)>>8
.(a+b+c+d+2)>>2
pour calculer une valeur de 0,5 pour la moyenne de la valeur? Qui semble assez normal chose à faire.Cela dépend du processeur et le compilateur. Certains compilateurs déjà d'optimiser le code de cette façon, d'autres ne le font pas.
Si vous avez besoin de vérifier à chaque fois que votre code doit être optimisé de cette façon.
Sauf si vous avez désespérément besoin pour optimiser, je ne voudrais pas brouiller mon code source juste pour enregistrer des instructions de montage ou du processeur.
>>
opérateur est plus rapide que/
et, si l'signé valeurs peuvent être négatives, il est souvent sémantiquement supérieure ainsi. Si on a besoin de la valeur quix>>4
serait de produire, c'est beaucoup plus clair quex < 0 ? -((-1-x)/16)-1 : x/16;
, et je ne peux pas imaginer comment un compilateur peut optimiser cette dernière expression à quelque chose d'agréable.Il pourrait ou ne pourrait pas être sur votre ordinateur - si vous vous souciez, la mesure dans votre usage du monde réel.
Une étude de cas - à partir de 486 core i7
L'analyse comparative est très difficile de le faire de façon significative, mais nous pouvons regarder un peu les faits. De http://www.penguin.cz/~literakl/intel/s.html#SAL et http://www.penguin.cz/~literakl/intel/je.html#IMUL nous avons une idée de x86 cycles d'horloge nécessaires pour le décalage et la multiplication. Dis nous en tenir à "486" (la dernière de la liste), 32 bits des registres et immédiates, IMUL prend 13-42 cycles et IDIV 44. Chaque SAL prend 2, et en ajoutant 1, de sorte que même avec un peu de ceux-ensemble décalage superficiellement ressemble à un gagnant.
Ces jours-ci, avec le core i7:
(à partir de http://software.intel.com/en-us/forums/showthread.php?t=61481)
(de certains Intel blurb)
Qui vous donne une idée de la façon dont beaucoup choses ont. L'optimisation de trivia - comme le décalage de bits contre
*
- qui a été pris au sérieux, même dans les années 90 est juste aujourd'hui obsolète. De décalage de bits est encore plus rapide, mais pour les non-puissance de deux mul/div par le temps de vous faire tous vos déplacements et ajouter les résultats, il est encore plus lent. Alors, plus d'instructions signifie plus de défauts de cache, plus les problèmes potentiels dans le pipelining, plus d'utilisation de ces registres peut signifier plus de sauvegarde et restauration du contenu du registre à partir de la pile... ça devient vite trop compliqué de quantifier tous les impacts définitivement, mais ils sont essentiellement négatifs.fonctionnalité dans le code source vs la mise en œuvre
Plus généralement, votre question est balisé le C et le C++. En tant que 3e génération langues, s'ils sont spécifiquement conçus pour cacher les détails de la sous-jacentes du PROCESSEUR à jeu d'instructions. Pour satisfaire leur langue les Normes, ils doivent soutenir la multiplication et le déplacement des opérations (et beaucoup d'autres) même si le matériel sous-jacent n'est pas. Dans de tels cas, ils doivent synthétiser le résultat requis à l'aide de beaucoup d'autres instructions. De même, ils doivent fournir le logiciel de soutien pour les opérations à virgule flottante si le CPU n'en a pas et il n'y a pas de FPU. Les Processeurs modernes supportent tous
*
et<<
, donc cela peut sembler absurde théoriques et historiques, mais l'importance c'est que la liberté de choisir la mise en œuvre va dans les deux sens: même si le CPU a une instruction qui met en œuvre l'opération demandée dans le code source dans le cas général, le compilateur est libre de choisir quelque chose d'autre qu'il préfère parce que c'est mieux pour la spécifiques cas, le compilateur est confronté à.Exemples (avec un hypothétique langage d'assemblage)
Instructions ou-exclusif (
xor
) n'ont aucun rapport avec le code source, mais xor-ing quoi que ce soit avec lui-même efface tous les bits, de sorte qu'il peut être utilisé pour définir quelque chose à 0. Le code Source qui implique des adresses de mémoire ne peut aboutir à être utilisé.Ce genre de hacks ont été utilisés aussi longtemps que les ordinateurs ont été autour. Dans les premiers jours de 3GLs, pour sécuriser le développeur de l'absorption de la sortie du compilateur a dû satisfaire de l'existant hardcore de la main-optimisation de la langue de l'assembly dev. de la communauté que le code produit n'est pas plus lent, plus détaillé ou sinon pire. Les compilateurs ont rapidement adopté beaucoup d'optimisations - ils devenu un meilleur centralisée magasin de il de toute assemblée de la langue programmeur pourrait éventuellement être, mais il y a toujours la chance qu'ils manquent un précis d'optimisation qui se trouve être essentiel dans un cas particulier - les humains peuvent, parfois, de noix et de tâtonner pour quelque chose de mieux alors que les compilateurs il suffit de faire comme ils ont dit jusqu'à ce que quelqu'un se nourrit que de l'expérience en retour.
Donc, même si le décalage et l'ajout est encore plus rapide sur certains matériels, alors le compilateur de l'écrivain susceptibles d'avoir travaillé exactement quand il est à la fois bénéfiques et sans danger.
Maintenabilité
Si vos modifications sur le matériel, vous pouvez recompiler et il va chercher à le PROCESSEUR cible et de faire un autre choix, alors que vous avez peu de chances de jamais vouloir revoir votre "optimisations" ou à la liste qui compilation environnements doivent utiliser la multiplication et de la qui devrait passer. Pensez à tous les non-puissance de deux bits décalés "optimisations" écrite de 10 ans qui sont maintenant en train de ralentir le code qu'ils sont en mesure de l'exécution sur les processeurs modernes...!
Heureusement, de bons compilateurs comme GCC peut généralement remplacer une série de bitshifts et de l'arithmétique avec un direct de multiplication lorsque aucune optimisation est activée (c'est à dire
...main(...) { return (argc << 4) + (argc << 2) + argc; }
->imull $21, 8(%ebp), %eax
) donc une recompilation peut aider, même sans en fixer le code, mais ce n'est pas garanti.Étrange bitshifting d'application du code de la multiplication ou de la division est beaucoup moins expressif de ce que vous étiez sur le plan conceptuel essaie de l'atteindre, de sorte que les autres développeurs seront confus par ce, et un confus programmeur est plus susceptible d'introduire des bogues ou de supprimer quelque chose d'essentiel dans un effort pour restaurer semblant de santé mentale. Si vous ne le faites non évidente des choses quand ils sont vraiment, de façon tangible, bénéfique, et document bien (mais ne faites pas de document d'autres trucs qui sont de toute façon intuitive), tout le monde sera plus heureux.
Solutions générales rapport à des solutions partielles
Si vous avez quelques connaissances supplémentaires, tels que votre
int
ne sera véritablement en stockant les valeursx
,y
etz
, alors vous pourriez être en mesure de travailler des instructions de travail pour ces valeurs et vous obtenez votre résultat plus rapidement que lorsque le compilateur n'a pas cette idée et a besoin d'une mise en œuvre qui fonctionne pour tous lesint
valeurs. Par exemple, pensez à votre question:Vous illustrer la multiplication, mais combien de division?
Selon la Norme C++ 5.8:
Donc, votre de décalage de bits a une mise en œuvre définies résultat lorsque
x
est négatif: il ne peut pas travailler de la même façon sur des machines différentes. Mais,/
fonctionne beaucoup plus prévisible. (Il ne peut pas être parfaitement cohérente, car les différentes machines peuvent avoir différentes représentations des nombres négatifs, et donc les différentes gammes, même quand il y a le même nombre de bits qui composent la représentation.)Vous pouvez dire "je n'aime pas... que
int
est le stockage de l'âge de l'employé, il ne peut jamais être négatif". Si vous avez ce genre de perspicacité particulière, alors oui, votre>>
sûr d'optimisation peut être passé par le compilateur, sauf si vous explicitement le faire dans votre code. Mais, c'est risqué et rarement utile car la plupart du temps vous n'aurez pas ce genre d'information, et d'autres programmeurs travaillant sur le même code ne saurez pas que vous avez pari de la maison à certaines des attentes des données vous serez manipulation... ce qui semble totalement sûr pour le changement pourrait se retourner contre à cause de votre "optimisation".Oui... comme mentionné ci-dessus, les nombres négatifs ont définie par l'implémentation du comportement lors de l' "divisé" par décalage de bits.
Juste essayé sur ma machine de la compilation :
Lors du démontage, il produit de sortie :
Cette version est plus rapide que votre main-code optimisé avec de la pure déplacement et plus.
- Vous vraiment jamais savoir ce que le compilateur va venir avec, il est donc préférable d'écrire tout simplement un normal de multiplication et de lui laisser optimiser la façon dont il veut, sauf dans des cas bien précis où vous savoir le compilateur ne peut pas optimiser.
vector<T>::size()
. Mon compilateur est très ancienne! 🙂Le déplacement est généralement beaucoup plus rapide que de multiplier au niveau de l'instruction mais vous pouvez très bien être en train de perdre votre temps à faire prématurée des optimisations. Le compilateur peut très bien réaliser ces optimisations au compile-time. Le faire vous-même permettra d'affecter la lisibilité et peut avoir aucun effet sur les performances. C'est probablement la peine de faire des choses comme ça si vous avez le profil trouvé ceci pour être un goulot d'étranglement.
En fait la division truc, connu comme "la magie de la division" peut effectivement générer d'énormes profits. Nouveau profil pour voir si c'est nécessaire. Mais si vous ne l'utilisez il y a des programmes utiles autour de vous pour vous aider à comprendre ce besoin d'instructions pour la même division de la sémantique. Voici un exemple : http://www.masm32.com/board/index.php?topic=12421.0
Un exemple que j'ai soulevé le cas des OP fil sur MASM32:
Générerait:
Maj entier et les instructions de multiplication ont des performances similaires sur la plupart des Processeurs modernes entier instructions de multiplication ont été relativement lente dans les années 1980, mais en général ce n'est plus vrai. Entier instructions de multiplication peut être plus élevé, latence, donc il peut encore y avoir des cas où un changement est préférable. Idem pour les cas où vous pouvez garder plus des unités d'exécution occupé (même si cela peut réduire à la fois les moyens).
Division entière est encore relativement faible, cependant, de sorte que l'aide d'un déplacement au lieu de la division par une puissance de 2 est encore une victoire, et la plupart des compilateurs de mettre en œuvre la présente comme une optimisation. Note cependant que, pour ce type d'optimisation pour être valide, le dividende doit être signé ou doivent être connus pour être positif. Pour un négatif de dividendes de la maj et fracture ne sont pas équivalentes!
De sortie:
Donc, si vous voulez aider le compilateur, alors assurez-vous que la variable ou l'expression que dans le dividende est explicitement non signé.
Il dépend entièrement sur le périphérique cible, la langue, objet, etc.
Pixel croquant dans un pilote de carte vidéo? Très probablement, oui!
.NET business application pour votre département? Absolument aucune raison même de le regarder.
Pour une haute performance de jeu pour un appareil mobile, il pourrait être utile dans la recherche, mais seulement après que plus facile optimisations ont été effectuées.
Ne pas faire, sauf si vous avez absolument besoin et votre code intention exige de déplacement plutôt que la multiplication ou la division.
En journée typique - vous pourrait potentiellement sauver quelques cycles machine (ou en vrac, depuis compilateur sait le mieux ce qui à optimiser), mais le coût n'est pas la peine - vous passer du temps sur des détails mineurs, plutôt que de véritables emplois, de maintenir le code devient plus difficile et vos collègues vont vous maudire.
Vous pourriez avoir besoin de le faire pour la haute charge des calculs, où chaque enregistré cycle de minutes de temps d'exécution. Mais, vous devez optimiser un lieu à un moment et de faire des tests de performances à chaque fois pour voir si vous avez vraiment fait plus rapide ou cassé compilateurs logique.
Autant que je sais que dans certaines machines de multiplication peuvent avoir besoin de jusqu'à 16 à 32 cycle de la machine. Donc Oui, selon le type de machine, bitshift opérateurs sont plus rapides que la multiplication ou la division.
Cependant, certaines machines ont leurs mathématiques processeur, qui contient des instructions pour la multiplication ou la division.
Je suis d'accord avec la réponse par Drew Hall. La réponse pourrait utiliser quelques notes supplémentaires si.
Pour la grande majorité des développeurs de logiciels le processeur et le compilateur ne sont plus pertinentes à la question. La plupart d'entre nous sont bien au-delà de la 8088 et MS-DOS. C'est peut-être seulement pour ceux qui sont encore en développement pour processeurs embarqués...
À ma société de logiciels de Mathématiques (add/sub/mul/div) doit être utilisé pour toutes les mathématiques.
Tout Changement doit être utilisé lors de la conversion entre les types de données, par exemple. ushort d'octets que le n>>8 et pas n/256.
Dans le cas des entiers signés et décalage à droite vs division, il peut faire une différence. Pour les nombres négatifs, le changement des tours de tours vers l'infini négatif alors que les cycles de division vers zéro. Bien sûr, le compilateur va changer la division de quelque chose de moins cher, mais il sera généralement le changer pour quelque chose qui a le même comportement d'arrondissage de division, parce qu'il est incapable de prouver que la variable ne sera pas négatif ou il n'a tout simplement pas de soins.
Donc, si vous pouvez prouver qu'un certain nombre ne sera pas négatif, ou si vous n'aimez pas la façon de les arrondir, vous pouvez faire de l'optimisation d'une manière qui est plus susceptible de faire une différence.
unsigned
Python test de l'exécution même de la multiplication de 100 millions de fois contre le même nombres aléatoires.
Donc en faisant une maj plutôt que la multiplication ou la division par une puissance de deux en python, il y a une légère amélioration (~10% pour la division; ~1% pour la multiplication). Si c'est un non-puissance de deux, il y a probablement un ralentissement considérable.
De nouveau ces #s va changer en fonction de votre processeur, votre compilateur (ou d'un interprète -- n'en python pour des raisons de simplicité).
Comme tout le monde, ne pas prématurément optimiser. Écriture très lisible le code, profil si ce n'est pas assez rapide, et ensuite d'essayer d'optimiser les parties lentes. Rappelez-vous, votre compilateur est beaucoup mieux à l'optimisation que vous êtes.
Il y a des optimisations du compilateur ne peut pas le faire parce qu'ils ne fonctionnent que pour un ensemble réduit de données.
Ci-dessous, il est en c++ exemple de code qui peut faire plus rapide de la division de faire un 64bits "Multiplication par l'inverse". Le numérateur et le dénominateur doivent être en dessous d'un certain seuil. Notez qu'il doit être compilé en 64 bits instructions pour être effectivement plus rapide que la normale de la division.
Je pense que dans le seul cas que vous voulez de multiplier ou de diviser par une puissance de deux, vous ne pouvez pas vous tromper avec l'aide de bitshift opérateurs, même si le compilateur convertit à une MUL/DIV, parce que certains processeurs microcode (vraiment, une macro) de toute façon, donc, pour ces cas, vous allez obtenir une amélioration, surtout si le décalage est supérieur à 1. Ou plus explicitement, si le CPU n'a pas de bitshift opérateurs, il sera un MUL/DIV de toute façon, mais si le CPU a bitshift opérateurs, vous éviter un microcode de la branche et c'est quelques instructions de moins.
Je suis en train d'écrire un peu de code à droite maintenant, qui nécessite beaucoup de doubler/réduction de moitié des opérations, car il fonctionne sur un réseau dense d'arbres binaires, et il y a encore une opération qui, je le soupçonne peut-être plus optimale qu'une plus - gauche (puissance de deux qui se multiplient) maj avec un ajout. Ce peut être remplacé par un virage à gauche et un xor si le décalage est plus large que le nombre de bits que vous souhaitez ajouter, exemple facile est (i<<1)^1, ce qui ajoute un à un doublé de valeur. Cela ne veut évidemment pas s'appliquer à un décalage à droite (puissance de deux fracture), car seule une gauche (little endian) maj comble le vide avec des zéros.
Dans mon code, ces multiplier/diviser par deux et les puissances de deux opérations sont très utilisées de manière intensive et parce que les formules sont assez court déjà, chaque instruction peut être éliminé peut être un gain substantiel. Si le processeur ne prend pas en charge ces bitshift opérateurs, aucun gain va se passer, mais il n'y aura une perte.
Aussi, dans les algorithmes que j'écris, ils représentent visuellement les mouvements qui se produisent dans ce sens, ils sont en fait de plus en plus clair. Le côté gauche d'un arbre binaire est plus grand, et le droit est plus petit. Ainsi que, dans mon code, étrange et même les nombres ont une signification particulière, et tous de gauche des enfants dans l'arbre sont curieux et tout à droite, de la main des enfants, et la racine sont même. Dans certains cas, que je n'ai pas rencontré encore, mais, oh, en fait, je n'ai même pas penser à cela, x&1 est peut-être plus un fonctionnement optimal par rapport à x%2. x&1 sur un même numéro de produire zéro, mais produira 1 pour un nombre impair.
Pour aller un peu plus loin que juste au pair/impair d'identification, si je suis nulle pour x&3 je sais que 4 est un facteur de notre nombre, et de même pour x%7 pour 8, et ainsi de suite. Je sais que ces cas ont probablement eu une utilité limitée, mais il est bon de savoir que vous pouvez éviter un module le fonctionnement et l'utilisation d'un bit à bit de la logique de fonctionnement au lieu de cela, parce que les opérations bit à bit sont presque toujours le plus rapide, et moins susceptibles d'être ambigu pour le compilateur.
Je suis à peu près d'inventer le domaine de l'dense des arbres binaires, donc je pense que les gens ne peuvent pas saisir la valeur de ce commentaire, que très rarement, les gens veulent seulement effectuer des factorisations uniquement sur les puissances de deux, ou seulement multiplier/diviser des puissances de deux.