Représentez le nombre en binaire, puis recherchez le bit le plus significatif (le bit non nul le plus élevé). Naïvement, vous pouvez le faire en décalant vers la droite un bit à la fois jusqu'à ce qu'il soit nul - c'était "un de trop". C'est en gros l'approche que vous avez essayée. Une recherche binaire serait un peu plus rapide. Pour un entier de 32 bits, décalez vers la droite de 16 ; si c'est toujours > 0, décalez vers la droite de 8, etc. Je suis sûr que vous pouvez trouver la solution à partir de là.
Exemple de code :
typedef unsigned long long int ulli;
ulli floor2(ulli num){
int msb = 8*sizeof(num)/2;
ulli temp = ((ulli)1)<<msb;
while(msb>1){
msb/=2; // using divide for clarity
if(temp>num) temp>>=msb; else temp<<=msb;
}
if (temp>num) temp/=2;
return temp;
}
J'ai effectué quelques tests de cet algorithme par rapport à l'algorithme de la topBit
ainsi que le builtIn
méthode. Une boucle avec 10M itérations, générant un nombre aléatoire "long", prend 362 ms sur mon système (sans optimisation du compilateur). Si la boucle inclut l'une des méthodes de calcul, les temps augmentent comme suit :
============= total net
builtin: 407 45
binary search: 579 215
topBit: 2295 1933
La méthode intégrée est certainement la plus rapide, et de loin, ce qui n'est pas vraiment surprenant ! Avec des nombres de 64 bits, topBit aura besoin en moyenne de 32 boucles (la moitié des bits étant activés, ils sont ignorés) et la méthode binaire de seulement 5 boucles, ce qui laisse espérer une différence de vitesse de 6x ; c'est à peu près ce que vous voyez. Lorsque je définis ulli
como unsigned short
(16 bits), la différence de temps est d'environ 2x.