Pourquoi on parle de moi? Je n'étais même pas présent. ![]()
" Et ta mère elle fait partie des gens qui sautent pour avoir des pièces, comme mario
"
Comme c'est petit. ![]()
Et puis, récemment, je faisais du c# sous unity (parce qu'il faut bien manger
), et il y avait un morceau de code assez critique comprenant une division entière par 256 qu'il fallait répéter des centaines de milliers de fois, et bien lorsque je l'ai remplacée par >>8, j'ai doublé mes performances, dis-moi Pocoio, où est ton dieu, maintenant?
Ici avant que dans ton cul, dans ta maman,...
mais non, tu penses bien que remplacer un "/ 256" (écrit EXPLICITEMENT, donc division par une CONSTANTE) par un décalage de bits, c'est trop en demander, un conseil, continue d'expérimenter des techniques d'optimisation manuelle si tu veux avoir du code performant, l'expérience montre que s'en relier entièrement au compilateur ne produit pas toujours de bons résultats. ![]()
C'est toi qui délire, tous les compilateurs font ça.
Et à noter que pour les divisions si le dividende peut être négatif (si c'est un nombre signé quoi) le compilateur doit faire un peu plus qu'un simple décalage car pour les entiers négatifs l'arrondi n'est pas conforme à la convention qui est d'arrondir vers zéro, au lieu de ça un décalage de bits arrondi toujours vers le bas.
Genre -17/4 devrait donner -4 mais avec un décalage de bit ça donnerait -5.
Oh, genre si je marque explicitement mes entiers en nombres non-signés (ce qui est le cas, ils n'ont jamais de valeurs négatives), le compilateur ferait l'optimisation quand même?
Vivement lundi matin que j'essaye. ![]()
"Encore un jeu de cube criard et où on comprend rien"
http://www.youtube.com/watch?v=DoCmdGpa6Kw
" si je marque explicitement mes entiers en nombres non-signés (ce qui est le cas, ils n'ont jamais de valeurs négatives), le compilateur ferait l'optimisation quand même?
"
Si tu les marque comme non signé il devrait pouvoir se contenter de faire un simple décalage. Pour la fonction suivante:
int func(unsigned int x)
{
return x/256;
}
J'obtiens ce code assembleur sous Visual Studio (best compiler, achetez-le, Microsoft c'est bien) :
mov eax, dword ptr [ebp+8]
shr eax, 8
J'ai pas copié le prologue et l'épilogue de la fonction, juste la partie qui correspond à l'opération, la première instruction récupère l'argument x sur la pile et le met dans le registre eax (qui est par convention celui dans lequel on met la valeur de retour) et fait un décalage vers la droite de 8 sur eax, rien de plus.
Maintenant pour cette fonction (où l'argument x est signé):
int func(int x)
{
return x/256;
}
Voici le code assembleur :
mov eax, dword ptr [ebp+8]
cdq
and edx, 0FFh
add eax, edx
sar eax, 8
Il y a en plus le calcul d'un bias que l'on ajoute à x, l'instruction cdq copie eax dans edx avec extension de signe on effectue un ET bit à bit de edx et de la constante 255 (tous les bits derrière le diviseur 256 autrement dit), ce qui nous donne le bias qu'on ajoute à l'argument x et on effectue le décalage sur cette valeur plutôt que de le faire directement sur x.
A noter aussi dans le deuxième exemple l'usage de sar plutôt que de shr dans le premier exemple, sar est un décalage arithmétique vers la droite, shr est un décalage logique vers la droite, mais cette différence n'a pas d'importance au niveau des perfs.
En C (ou C++ ou whatever) on pourrait aussi écrire ça:
(x<0 ? x+(1<<k)-1 : x) >> k
Ça donne l'arrondi correct avec un décalage de k vers la droite mais c'est moins efficace.
Ce n'est pas un dragon qui est caché par là-bas, ce sont des gemmes ainsi qu'une fée permettant d'avoir la super-flamme permanente.
Je pense que vous parliez plutôt du niveau treetop où il faut suivre un voleur parmi des pentes de super-charge pour comprendre comment se rendre sur une plate-forme lointaine en apparence.
http://www.youtube.com/watch?v=bpaZuIaLw4A#t=37s
Merci pour les exemples en assembleur, ça me rappelle que j'aurais pas dû sécher les cours dessus, encore qu'on ne travaillait que sur GCC et que c'est galère d'accéder au code assembleur de celui-ci en l'absence d'IDE vraiment important.
Oh, tant qu'à faire, parlons de l'opérateur conditionnel, que vaut-il vraiment? Ca permet d'éviter le branching, ou c'est juste pour écrire moins de if et de else pour attribuer des valeurs? ![]()
" Oh, tant qu'à faire, parlons de l'opérateur conditionnel, que vaut-il vraiment? Ca permet d'éviter le branching, ou c'est juste pour écrire moins de if et de else pour attribuer des valeurs?
"
Ça peut éventuellement éviter le branching oui, je veux bien fournir des exemples en assembleur aussi, be back in a sec, le temps de générer tout ça.
enfin je sais que c'est super nul d'utiliser cet opérateur avec des fonctions à la place des deux valeurs de retour, car il exécute les deux fonctions, à utiliser avec prudence, donc. ![]()
Ah oui effectivement, j'avais oublié le dragon que l'on peut entendre depuis le rez-de-chaussée. Ceci dit, c'est un dragon extrêmement facile à obtenir. Il vous a vraiment fallu des années ou c'est une exagération ?
Moi le jeu buguait dès que j’essayais d'aller au dernier niveau bonus.
Comme si libérer 80 dragons n'était pas assez chiant comme ça ...
* Posté le 4 août 2013 à 23:16:06 Avertir un administrateur
* Moi le jeu buguait dès que j’essayais d'aller au dernier niveau bonus.
Comme si libérer 80 dragons n'était pas assez chiant comme ça ...
cette N, le jeu qui plante lorsque tu es enfin prêt à découvrir la Vérité de ce qu'il se cache derrière cette porte... ![]()
" enfin je sais que c'est super nul d'utiliser cet opérateur avec des fonctions à la place des deux valeurs de retour, car il exécute les deux fonctions, à utiliser avec prudence, donc.
"
Pas forcément, y'a plein de façon d'implémenter une expression conditionnelle, mais c'est vrai que dans certains cas on peut évaluer les deux résultats et faire simplement un transfert de données conditionnel genre avec l'instruction CMOVx dest, src où x est une condition (genre CMOVG pour greater ou CMOVL pour less) et où on copie la source dans la destination que si la condition est vraie (on effectue une instruction cmp au préalable pour que les bits dans le registre des flags soit correctement allumés).
En gros on calcule les deux valeurs, on en met une des deux valeurs dans le registre eax, après grâce à l'instruction CMOVx on copie l'autre résultat si il se révèle être le bon ou on garde celui qu'on a mit au départ autrement, on évité de faire un saut conditionnel comme ça.
Après certains compilateurs ne veulent pas utiliser l'instruction CMOVx car elle était pas présente à la base, elle est apparue avec le Pentium Pro qui est assez vieux mais toujours est-il qu'un programme qui utilise cette instruction ne devrait pas tourner correctement sur un processeur plus vieux que ça.
Gosh, lire ça vaut bien la peine de subir des millions de remarques sur les mamans et les patrons, merci pour tout ce Savoir
![]()
Je suis en train d'essayer de faire en sorte que Visual Studio génère du code avec l'instruction CMOV d'ailleurs mais je n'y arrive pas, même avec l'option /arch:SSE2 ( http://msdn.microsoft.com/fr-fr/library/vstudio/7t5yh4fd.aspx ) qui devrait permettre d'utiliser ce genre d'instructions.
Il paraît que le compilateur de microsoft et les intrinsics...
J'ai déjà vu des exemples de codes compilés avec lui et gcc, pour lequel gcc en faisait du 30% plus performant avec une chiée d'optimisations affreusement dépendantes de l'architecture et de dangereuses optimisations des nombres flottants, et pourtant toutes les options d'optimisations que j'ai pu trouver dans visual pour la version MSVC, les deux produisant un résultat similaire (encodage de texture, avec mobilisation assez massive de nombres flottants). ![]()