Puissances de 2 et optimisation de poils de nez

Puissances de 2 et optimisation de poils de nez - C++ - Programmation

Marsh Posté le 19-09-2002 à 19:47:26    

Youhou. Est-ce que quelqu'un aurait une solution rapide pour déterminer la puissance de 2 immédiatement supérieure à un entier positif quelconque ? Plus concrètement, pour determiner n tel que k n'existe pas avec size<=2^k<2^n, si size est l'entier positif quelconque considéré. Pour le moment, j'ai écrit une fonction moche qui le fait (cf plus loin) mais c'est très lent.
Si quelqu'un a une idée, je suis preneur (peu importe que la solution rendue soit n ou 2^n). Merci d'avance.
 
int expDeux(int x) {
  int k=0;
  int p=1;
  while (p<x) {
    k++;
    p<<=1;
  }
  return k;
}

Reply

Marsh Posté le 19-09-2002 à 19:47:26   

Reply

Marsh Posté le 19-09-2002 à 19:51:30    

tu masques, tu gardes le bit le plus a gauche de ton entier et tu decales de 1 vers la gauche


Message édité par HappyHarry le 19-09-2002 à 19:52:39
Reply

Marsh Posté le 19-09-2002 à 19:56:13    

HappyHarry a écrit a écrit :

tu masques, tu gardes le bit le plus a gauche de ton entier et tu decales de 1 vers la gauche




 
Euh j'ai pas compris. Tu masques avec quoi ? Et d'ailleurs sauf erreur de ma part, si tu appliques cette méthode en bourrin pour 8 tu obtiendras 16 ce qui n'est pas vraiment le but recherché. Donc silteplait ecris moi un bout de code rapide qui implémente ta methode (ou alors décris au moins le masque). Si c'est plus rapide que ma fonction, eh bien bravo et merci:)


Message édité par exo_ le 19-09-2002 à 19:58:37
Reply

Marsh Posté le 19-09-2002 à 20:04:53    

Certes, mais comment fait-il pour générer son masque puisqu'il ne sait pas a priori où est le bit le plus à gauche ? En fait il me semble qu'il existe une instruction x86 pour le savoir, mais ça ne sera pas portable... Sinon il faut le chercher, ce qui n'est pas plus rapide que la fonction qu'il a déja écrite.


Message édité par matafan le 19-09-2002 à 20:07:10
Reply

Marsh Posté le 19-09-2002 à 20:09:15    

ben jusqu'a preuve du contraire, 16 est la puissance de 2 immédiatement supérieure a 8 ... m'enfin bon ...*
 
dans l'idée c :
 
le but est de masquer les bits de poids les plus faibles
 
ex : 0011 1001 pour obtenir 0010 0000
 
d'ou un masque 0001 1001
 
ce qui fait que 0011 1001 XOR 0001 1001 te donne 0010 0000
 
et 0010 0000 <<= 1 te donne la puissance de 2 immédiatement supérieure

Reply

Marsh Posté le 19-09-2002 à 20:12:33    

Bon tu n'as pas du comprendre le problème... Le masque "0001 1001", tu l'obtiens comment ? Il n'est pas plus facile à obtenir que le "0010 0000", ou même directement "0100 0000" :heink:

Reply

Marsh Posté le 19-09-2002 à 20:18:23    

Matafan a écrit a écrit :

Bon tu n'as pas du comprendre le problème... Le masque "0001 1001", tu l'obtiens comment ? Il n'est pas plus facile à obtenir que le "0010 0000", ou même directement "0100 0000" :heink:  




 
 
oué bon g rien dit ...
je sais que c possible, mais j'me souviens plus ...
 
j'ai une autre soluce en stock, j'vais manger


Message édité par HappyHarry le 19-09-2002 à 20:20:13
Reply

Marsh Posté le 19-09-2002 à 20:25:59    

si tu fais
 
(x - (x>>1)) << 1  
c'est pas bon ?

Reply

Marsh Posté le 19-09-2002 à 20:40:09    

wpk a écrit a écrit :

si tu fais
 
(x - (x>>1)) << 1  
c'est pas bon ?




 
nan

Reply

Marsh Posté le 19-09-2002 à 20:41:51    

bon ma soluce avec le masque marche, mais ne sera plus rapide que lorsque l'on est relativement proche de la capacité max du type utilisé
suffit de décaler vers la gauche jusqu'a obtenir 1, et de redécaler ce qu'on a ainsi obtenu d'autant de fois vers la droite
ensuite le XOR, et ensuite le décalage de 1 vers la gauche

Reply

Marsh Posté le 19-09-2002 à 20:41:51   

Reply

Marsh Posté le 19-09-2002 à 20:45:52    

En passant par la valeur hexa (sprintf avec %x) et en "jouant" avec le caractère de gauche ? Idée comme ça, mais faudrait approfondir :D.

Reply

Marsh Posté le 19-09-2002 à 20:47:31    

carbon_14 a écrit a écrit :

En passant par la valeur hexa (sprintf avec %x) et en "jouant" avec le caractère de gauche ? Idée comme ça, mais faudrait approfondir :D.




 
spa con
 
 
tain ca fait tellement longtemps que j'ai plus joué avec ca en C que j'ai presque oublié tous les ptits trucs  [:zoutte]

Reply

Marsh Posté le 19-09-2002 à 20:50:51    

Hou on est parti dans des trucs là :D Moi je dis, c'est soit avec un ch'tit bout d'assembleur (avec la fameuse instruction qui donne la position du premier bit à 1), soit une solution qui ne sera pas plus rapide que ce que tu as déjà.

Reply

Marsh Posté le 19-09-2002 à 20:51:40    

HappyHarry a écrit a écrit :

bon ma soluce avec le masque marche, mais ne sera plus rapide que lorsque l'on est relativement proche de la capacité max du type utilisé
suffit de décaler vers la gauche jusqu'a obtenir 1, et de redécaler ce qu'on a ainsi obtenu d'autant de fois vers la droite
ensuite le XOR, et ensuite le décalage de 1 vers la gauche




 
remarque que si ton entier occupe effectivement tous les octets du type utilisé, un  
 
2 puissance ((8 * nombre d'octets) - (nombre de decalages a gauche faits jusqu'a obtenir 1  -  1))
 
fait aussi l'affaire je crois
 
c valable dans tous les cas ou tu connais le nombre d'octes utilisés par ton entier

Reply

Marsh Posté le 19-09-2002 à 20:52:41    

Matafan a écrit a écrit :

Hou on est parti dans des trucs là :D Moi je dis, c'est soit avec un ch'tit bout d'assembleur (avec la fameuse instruction qui donne la position du premier bit à 1), soit une solution qui ne sera pas plus rapide que ce que tu as déjà.




 
ben j'crois me souvenir qu'il  a moyen de l'obtenir aussi en C, mais je sais plus comment
 
ps : avec ce genre de question, fallait s'y attendre

Reply

Marsh Posté le 19-09-2002 à 21:01:48    

Code :
  1. int function p2sup(int nb)
  2. {
  3. int j=1;
  4. int p=0;
  5. while (1)
  6.   {
  7.    p+=j;
  8.    if (nb <= p) break;
  9.    p+=j;
  10.    j++;
  11.   }
  12. return j;
  13. }


p2sup(80) =>  9
p2sup(81) =>  9
p2sup(82) => 10
 
Voilà une solution simple :D.


---------------
Le site de l'année :D (XHTML 1.0 strict) : http://darkoli.free.fr/index.html
Reply

Marsh Posté le 19-09-2002 à 21:43:58    

Ca donne pas la racine ?  
Il voudrait la puissance de deux juste supérieure au nombre entré
 
p2sup(80) => 128  
p2sup(81) => 128  
p2sup(82) => 128  
 
p2sup(127) => 128  
p2sup(128) => 256
 
 
 

Reply

Marsh Posté le 19-09-2002 à 21:49:03    

HappyHarry a écrit a écrit :

ben jusqu'a preuve du contraire, 16 est la puissance de 2 immédiatement supérieure a 8 ... m'enfin bon ...




 
Euh désolé si mes notations matheuses sont un peu tordues mais "determiner n tel que k n'existe pas avec size<=2^k<2^n, si size est l'entier positif quelconque considéré" signifie que si size=8 alors n=3 soit 2^n=8.

Reply

Marsh Posté le 19-09-2002 à 21:54:36    

HappyHarry a écrit a écrit :

 
2 puissance ((8 * nombre d'octets) - (nombre de decalages a gauche faits jusqu'a obtenir 1  -  1))
 
fait aussi l'affaire je crois




 
Euh le problème alors c'est de déterminer le nombre de décalages à gauche pour arriver à 0..01. En programmeur moyen que je suis, j'implémente ce genre de choses avec une bonne grosse boucle. Donc niveau performance, c'est assez moyen.

Reply

Marsh Posté le 19-09-2002 à 22:03:50    

exo_ a écrit a écrit :

 
 
Euh le problème alors c'est de déterminer le nombre de décalages à gauche pour arriver à 0..01. En programmeur moyen que je suis, j'implémente ce genre de choses avec une bonne grosse boucle. Donc niveau performance, c'est assez moyen.




 
jusqu'a ce que le bit que tu **sors** a gauche soit egal a 1, ce qui sur un nombre grand, meme dans une boucle, prend moins de temps que de boucler en decalant vers la gauche et en testant si c superieur ou pas

Reply

Marsh Posté le 19-09-2002 à 22:06:38    

En amateur sous-moyen :D, j'avais une fois essayé de remplacer des divisions par des décalages, mais ça m'apportait pas de gain du tout en vitesse. J'ai été déçu.
 
Si on divise le nombre par deux, n fois, en comptant le nombre de divisions, et ajoutant un => puiss de deux supérieure (genre division euclidienne).


Message édité par Carbon_14 le 19-09-2002 à 22:07:17
Reply

Marsh Posté le 19-09-2002 à 22:12:00    

exo_ a écrit a écrit :

 
 
Euh désolé si mes notations matheuses sont un peu tordues mais "determiner n tel que k n'existe pas avec size<=2^k<2^n, si size est l'entier positif quelconque considéré" signifie que si size=8 alors n=3 soit 2^n=8.




 
et pis une fois que t'as sorti le bit le plus a gauche, si ce qui reste = 0, alors c que ton nombre de depart est une puissance de 2, donc c fini aussi, na !

Reply

Marsh Posté le 19-09-2002 à 22:15:01    

Au feeling :
Si tu divises par 16, on peut determiner dans quelle zone se trouve le bit supérieur.
Ensuite y a juste à faire un ET (masquage) avec les 4 patterns commencant par 1000 , 0100, 0010 et 0001. (le nombre de zéro après dépend du résultat de la division par 16. Si c'est 0, y en a pas, si c'est 1, c'est 0000, si c'est 2 c'est 0000 0000, etc)
Le premier resultat qui renvoie autre chose que 0 te donne la position du premier 1 :)


Message édité par joce le 19-09-2002 à 22:16:47

---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:18:17    

carbon_14 a écrit a écrit :

En amateur sous-moyen :D, j'avais une fois essayé de remplacer des divisions par des décalages, mais ça m'apportait pas de gain du tout en vitesse. J'ai été déçu.
 
Si on divise le nombre par deux, n fois, en comptant le nombre de divisions, et ajoutant un => puiss de deux supérieure (genre division euclidienne).




 
ce qui equivaut donc a decaler a droite jusqu'a ce que tu obtiennes 0
on y arrive :)
 
 
algo : avec x un entier positif quelconque
 
int aTester = x;
int tmpTest = x;
int tmpBit;
int resu;
int nbDecalages = 0;
bool estPuisDeux = true;
 
while (tmpTest>0)
{
tmpBit = tmpTest >> 1;
if (tmpBit==1) estPuisDeux = false;
tmpTest >>= 1;
nbDecalages++;
}
 
if (estPuisDeux)  
{
resu = aTester;
}
else
{
resu = 2^(nbDecalages + 1)
}
 
 
edit : mais c sur que ca sera ptet pas plus rapide


Message édité par HappyHarry le 19-09-2002 à 22:20:11
Reply

Marsh Posté le 19-09-2002 à 22:20:21    

Exemple :
 

T'as 24 :
 
00110000
 
floor (24/16) => 1
 
tu testes 0011 0000 AND 1000 0000 => c'est pas bon
          0011 0000 AND 0100 0000 => c'est pas bon
          0011 0000 AND 0010 0000 => ok c'est != 0
 
donc la puissance supérieure c'est 0100 0000


 
 


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:21:22    

HappyHarry a écrit a écrit :

 
 
ce qui equivaut donc a decaler a droite jusqu'a ce que tu obtiennes 0
on y arrive :)
 
 
algo : avec x un entier positif quelconque
 
int aTester = x;
int tmpTest = x;
int tmpBit;
int resu;
int nbDecalages = 0;
bool estPuisDeux = true;
 
while (tmpTest>0)
{
tmpBit = tmpTest >> 1;
if (tmpBit==1) estPuisDeux = false;
tmpTest >>= 1;
nbDecalages++;
}
 
if (estPuisDeux)  
{
resu = aTester;
}
else
{
resu = 2^(nbDecalages + 1)
}
 
 
edit : mais c sur que ca sera ptet pas plus rapide




je préfère ma méthode, y a qu'une division et 3 tests (au pire) :D


Message édité par joce le 19-09-2002 à 22:21:46

---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:23:58    

HappyHarry a écrit a écrit :

 
 
jusqu'a ce que le bit que tu **sors** a gauche soit egal a 1, ce qui sur un nombre grand, meme dans une boucle, prend moins de temps que de boucler en decalant vers la gauche et en testant si c superieur ou pas




 
Bah là aussi il faut tester les chiffres que tu sors. Car si par hasard ils s'amusent à être tous nuls, eh bien alors il faut retourner le chiffre tel quel. Par ailleurs, afin d'obtenir le nombre de chiffres ainsi giclés, il est de bon ton d'utiliser un truc genre "nb++". Et personne ne me fera croire que INCL a besoin de moins de cycles pour s'exécuter que SHL (ou alors les gens qui font des Pentium sont plutôt nuls et non jamais entendus parler des registres à décalage ce qui m'étonnerait beaucoup). Bref de toute façon, vu le calcul final à effectuer avec ta méthode et comme je suis feignant, je reste persuadé que ma solution est meilleure que la tienne. Mais merci quand même de perdre du temps là dessus.

Reply

Marsh Posté le 19-09-2002 à 22:25:30    

Pour les paresseux (comme moi :D)
unsigned long Bit[] = { // puissances de deux, précalculées
       0x1L,        0x2L,        0x4L,        0x8L,
      0x10L,       0x20L,       0x40L,       0x80L,
     0x100L,      0x200L,      0x400L,      0x800L,
    0x1000L,     0x2000L,     0x4000L,     0x8000L,
   0x10000L,    0x20000L,    0x40000L,    0x80000L,
  0x100000L,   0x200000L,   0x400000L,   0x800000L,
 0x1000000L,  0x2000000L,  0x4000000L,  0x8000000L,
0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
 
On compare jusqu'à trouver...
 
(Ca me sert à compacter des options d'un prog bit à bit sur un long, je voulais éviter les puissances de 2 dynamiques :D).

Reply

Marsh Posté le 19-09-2002 à 22:26:20    

exo_ a écrit a écrit :

 
 
Bah là aussi il faut tester les chiffres que tu sors. Car si par hasard ils s'amusent à être tous nuls, eh bien alors il faut retourner le chiffre tel quel. Par ailleurs, afin d'obtenir le nombre de chiffres ainsi giclés, il est de bon ton d'utiliser un truc genre "nb++". Et personne ne me fera croire que INCL a besoin de moins de cycles pour s'exécuter que SHL (ou alors les gens qui font des Pentium sont plutôt nuls et non jamais entendus parler des registres à décalage ce qui m'étonnerait beaucoup). Bref de toute façon, vu le calcul final à effectuer avec ta méthode et comme je suis feignant, je reste persuadé que ma solution est meilleure que la tienne. Mais merci quand même de perdre du temps là dessus.




 
j'ai jamais dit le contraire, j'ai d'ailleurs précisé plus haut que cette methode n'est plus rapide que dans le cas ou tu te rapproches de la capacité max du type utilisé ;)

Reply

Marsh Posté le 19-09-2002 à 22:33:33    

joce a écrit a écrit :

Exemple :
 

T'as 24 :
 
00110000
 
floor (24/16) => 1
 
tu testes 0011 0000 AND 1000 0000 => c'est pas bon
          0011 0000 AND 0100 0000 => c'est pas bon
          0011 0000 AND 0010 0000 => ok c'est != 0
 
donc la puissance supérieure c'est 0100 0000






 
Euh c'est séduisant mais je n'ai rien compris :) Le 16 de "floor(24/16)", il sort d'où ? Il faut le calculer, non ? Avec une bonne vieille boucle ? En outre, qui me dit que celui qui a codé "floor" n'est pas un immonde amateur et que son truc ne prend pas un quart d'heure à faire son calcul (je suis un peu de mauvaise foi) ? En fait à la base, quand j'ai posé la question, j'entretenais secrètement l'espoir que quelqu'un aurait une solution magique à base de % et & qui tiendrait en une ligne... Là pour le moment si optimisation il y a, c'est assez négligeable. Mais merci beaucoup en tout cas.

Reply

Marsh Posté le 19-09-2002 à 22:37:12    

exo_ a écrit a écrit :

 
 
Euh c'est séduisant mais je n'ai rien compris :) Le 16 de "floor(24/16)", il sort d'où ? Il faut le calculer, non ? Avec une bonne vieille boucle ? En outre, qui me dit que celui qui a codé "floor" n'est pas un immonde amateur et que son truc ne prend pas un quart d'heure à faire son calcul (je suis un peu de mauvaise foi) ? En fait à la base, quand j'ai posé la question, j'entretenais secrètement l'espoir que quelqu'un aurait une solution magique à base de % et & qui tiendrait en une ligne... Là pour le moment si optimisation il y a, c'est assez négligeable. Mais merci beaucoup en tout cas.




non c'est tout le temps 16
ca te permet d'obtenir dans quelle zone de quatre bits se trouve le 1 que tu cherches. (vu 0F correspond à 1111, FF à 1111 1111, etc)


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:37:46    

HappyHarry a écrit a écrit :

 
 
j'ai jamais dit le contraire, j'ai d'ailleurs précisé plus haut que cette methode n'est plus rapide que dans le cas ou tu te rapproches de la capacité max du type utilisé ;)




 
Et malheureusement ce n'est pas mon cas... En fait, mon problème à la base, c'est d'implémenter l'algorithme de gestion de la mémoire dit "buddy system" (je précise pour les amateurs de ce genre de saloperies). Or, sous le contexte restreint de mon projet, les allocations sont assez rarement supérieures à 2^16.

Reply

Marsh Posté le 19-09-2002 à 22:41:58    

autre exemple tout con, pour 78 :
 
floor (78 / 16) = 4
 
donc faut foutre 0000 0000 0000 0000
et tester :
 
1000 0000 0000 0000 0000
0100 0000 0000 0000 0000
0010 0000 0000 0000 0000
sinon c'est
0001 0000 0000 0000 0000
 
3 tests max
 
et si la division par 16 tombe juste en plus t'as directement la position du 1.


Message édité par joce le 19-09-2002 à 22:42:12

---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:42:34    

exo_ a écrit a écrit :

 
 
Et malheureusement ce n'est pas mon cas... En fait, mon problème à la base, c'est d'implémenter l'algorithme de gestion de la mémoire dit "buddy system" (je précise pour les amateurs de ce genre de saloperies). Or, sous le contexte restreint de mon projet, les allocations sont assez rarement supérieures à 2^16.




 
g rien dit alors ;)

Reply

Marsh Posté le 19-09-2002 à 22:44:02    

joce a écrit a écrit :

autre exemple tout con, pour 78 :
 
floor (78 / 16) = 4
 
donc faut foutre 0000 0000 0000 0000
et tester :
 
1000 0000 0000 0000 0000
0100 0000 0000 0000 0000
0010 0000 0000 0000 0000
sinon c'est
0001 0000 0000 0000 0000
 
3 tests max
 
et si la division par 16 tombe juste en plus t'as directement la position du 1.




 
 :ouch:  
 
si seulement on bidouillait en binaire pour le web, le forum marcherait presque bien  :D


Message édité par HappyHarry le 19-09-2002 à 22:44:24
Reply

Marsh Posté le 19-09-2002 à 22:45:09    

HappyHarry a écrit a écrit :

 
 
 :ouch:  
 
si seulement on bidouillait en binaire pour le web, le forum marcherait presque bien  :D



me suis planté c'est pas 0000 0000 0000 0000 c'est 0000 0000 0000 :D


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:45:48    

joce a écrit a écrit :

autre exemple tout con, pour 78  
floor (78 / 16) = 4
 
donc faut foutre 0000 0000 0000 0000
et tester :
 
1000 0000 0000 0000 0000
0100 0000 0000 0000 0000
0010 0000 0000 0000 0000
sinon c'est
0001 0000 0000 0000 0000
 
3 tests max
 
et si la division par 16 tombe juste en plus t'as directement la position du 1.




 
C'est mignon tout plein. Reste à savoir si floor est un truc rapide ou pas. Je vais essayer de faire un test de perf.

Reply

Marsh Posté le 19-09-2002 à 22:46:19    

joce a écrit a écrit :

 me suis planté c'est pas 0000 0000 0000 0000 c'est 0000 0000 0000 :D




 
d'ou le 'presque'  :p

Reply

Marsh Posté le 19-09-2002 à 22:48:20    

faut faire :
 
 
depart = (floor (size/16)) * 16;
 
décaler depart de 4 bits vers la gauche, et commencer les tests :D


---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le 19-09-2002 à 22:59:07    

Pour moi ca c'est suffisant :
 

Code :
  1. depart = ((floor (size/16)) * 16) << 4;
  2. if (size & depart)
  3.     result = depart<<1;
  4. else if (size & (depart>>1))
  5.     result = depart;
  6. else if (size & (depart>>2))
  7.     result = depart>>1;
  8. else
  9.     result = depart>>2;


Message édité par joce le 19-09-2002 à 23:14:07

---------------
Protèges carnets personnalisés & accessoires pour bébé
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed