Aujourd'hui, j'avais besoin d'un algorithme simple pour vérifier si un nombre est une puissance de 2.
L'algorithme doit être :
- Simple
- Correct pour tout
ulong
valeur.
J'ai trouvé cet algorithme simple :
private bool IsPowerOfTwo(ulong number)
{
if (number == 0)
return false;
for (ulong power = 1; power > 0; power = power << 1)
{
// This for loop used shifting for powers of 2, meaning
// that the value will become 0 after the last shift
// (from binary 1000...0000 to 0000...0000) then, the 'for'
// loop will break out.
if (power == number)
return true;
if (power > number)
return false;
}
return false;
}
Mais ensuite j'ai pensé, comment vérifier si log
<code>2</code>x
est un nombre exactement rond ? Mais quand j'ai vérifié pour 2^63+1, Math.Log
a donné exactement 63 à cause de l'arrondi. J'ai donc vérifié si 2 à la puissance 63 est égal au nombre d'origine - et c'est le cas, car le calcul est fait en double
et non en nombre exact :
private bool IsPowerOfTwo_2(ulong number)
{
double log = Math.Log(number, 2);
double pow = Math.Pow(2, Math.Round(log));
return pow == number;
}
Ce retour true
pour la valeur erronée donnée : 9223372036854775809
.
Existe-t-il un meilleur algorithme ?
1 votes
Je pense que la solution
(x & (x - 1))
peut renvoyer des faux positifs lorsqueX
est une somme de puissances de deux, par ex.8 + 16
.46 votes
Tous les nombres peuvent être écrits comme une somme de puissances de deux, c'est pourquoi nous pouvons représenter n'importe quel nombre en binaire. En outre, votre exemple ne renvoie pas un faux positif, car 11000 & 10111 = 10000 != 0.
2 votes
@JoeBrown Il n'y a pas de faux positifs. En fait, l'expression renvoie la plus grande de toutes les sommes de deux puissances de deux.