Aujourd'hui, j'avais besoin d'un algorithme simple pour vérifier si un nombre est une puissance de 2.
L'algorithme doit être:
ulong
.Je suis venu avec 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, je me suis demandé si je vérifierais si log2 x
est un nombre tout à fait rond. Mais lorsque j'ai vérifié 2 ^ 63 + 1, Math.Log
est retourné exactement 63 en raison de l'arrondissement. 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 effectué dans double
s et non pas en chiffres exacts:
private bool IsPowerOfTwo_2(ulong number)
{
double log = Math.Log(number, 2);
double pow = Math.Pow(2, Math.Round(log));
return pow == number;
}
Ceci a retourné true
pour la valeur incorrecte donnée: 9223372036854775809
.
Y a-t-il un meilleur algorithme?
Il y a une astuce simple pour ce problème:
bool IsPowerOfTwo(ulong x)
{
return (x & (x - 1)) == 0;
}
Notez que cette fonction signalera true
pour 0
, qui n'est pas une puissance de 2
. Si vous voulez exclure cela, voici comment:
bool IsPowerOfTwo(ulong x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
Tout d’abord le binaire et l’opérateur au niveau du bit de la définition MSDN:
Les opérateurs binaires et sont prédéfinis pour les types intégraux et bool. Pour les types intégraux, & calcule le ET logique au niveau des bits de ses opérandes. Pour les opérandes bool, & calcule le ET logique de ses opérandes; c'est-à-dire que le résultat est vrai si et seulement si ses deux opérandes sont vrais.
Voyons maintenant comment cela se passe:
La fonction retourne une valeur booléenne (true/false) et accepte un paramètre entrant de type unsigned long (x, dans ce cas). Supposons, par souci de simplicité, que quelqu'un ait passé la valeur 4 et appelle la fonction ainsi:
bool b = IsPowerOfTwo(4)
Nous remplaçons maintenant chaque occurrence de x par 4:
return (4 != 0) && ((4 & (4-1)) == 0);
Eh bien, nous savons déjà que 4! = 0 évaluations sont vraies, jusqu’ici tout va bien. Mais qu'en est-il:
((4 & (4-1)) == 0)
Cela se traduit bien sûr par ceci:
((4 & 3) == 0)
Mais en quoi consiste exactement 4&3
?
La représentation binaire de 4 est 100 et la représentation binaire de 3 est 011 (rappelez-vous que & prend la représentation binaire de ces nombres). Nous avons donc:
100 = 4
011 = 3
Imaginez que ces valeurs s’empilent un peu comme une addition élémentaire. L'opérateur &
indique que si les deux valeurs sont égales à 1, le résultat est 1, sinon il est 0. Donc 1 & 1 = 1
, 1 & 0 = 0
, 0 & 0 = 0
et 0 & 1 = 0
. Alors on fait le calcul:
100
011
----
000
Le résultat est simplement 0. Nous allons donc revenir en arrière et regarder ce que notre déclaration de retour traduit maintenant par:
return (4 != 0) && ((4 & 3) == 0);
Ce qui se traduit maintenant par:
return true && (0 == 0);
return true && true;
Nous savons tous que true && true
est simplement true
, et cela montre que pour notre exemple, 4 est une puissance de 2.
Certains sites qui documentent et expliquent ceci et d'autres bidouilles sont:
Et leur grand-mère le livre "Hacker's Delight" de Henry Warren, Jr. :
Comme la page de Sean Anderson explique, l'expression ((x & (x - 1)) == 0)
indique incorrectement que 0 est une puissance de 2. Il suggère d'utiliser:
(!(x & (x - 1)) && x)
pour corriger ce problème.
return (i & -i) == i
bool IsPowerOfTwo(ulong x)
{
return x > 0 && (x & (x - 1)) == 0;
}
J'ai récemment écrit un article à ce sujet sur http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/ . Il couvre le comptage de bits, comment utiliser les logarithmes correctement, le contrôle classique "x &&! (X & (x - 1))", et autres.
Voici une solution simple C++ :
bool IsPowerOfTwo( unsigned int i )
{
return std::bitset<32>(i).count() == 1;
}
bool IsPowerOfTwo(int n)
{
if (n > 1)
{
while (n%2 == 0)
{
n >>= 1;
}
}
return n == 1;
}
Et voici un algorithme général pour déterminer si un nombre est une puissance d'un autre nombre.
bool IsPowerOf(int n,int b)
{
if (n > 1)
{
while (n % b == 0)
{
n /= b;
}
}
return n == 1;
}
Le complément suivant à la réponse acceptée peut être utile à certaines personnes:
Une puissance de deux, exprimée en binaire, ressemblera toujours à 1 suivie de n zéros où n est supérieur ou égal à 0. Ex:
Decimal Binary
1 1 (1 followed by 0 zero)
2 10 (1 followed by 1 zero)
4 100 (1 followed by 2 zeroes)
8 1000 (1 followed by 3 zeroes)
. .
. .
. .
etc.
Lorsque nous soustrayons 1
de ce type de nombres, ils deviennent 0 suivis de n uns et n est identique à ci-dessus. Ex:
Decimal Binary
1 - 1 = 0 0 (0 followed by 0 one)
2 - 1 = 1 01 (0 followed by 1 one)
4 - 1 = 3 011 (0 followed by 2 ones)
8 - 1 = 7 0111 (0 followed by 3 ones)
. .
. .
. .
etc.
Venir au coeur
Que se passe-t-il lorsque nous faisons un bit AND au niveau d'un nombre
x
, qui est une puissance de 2, etx - 1
?
Celui de x
s'aligne sur le zéro de x - 1
et tous les zéros de x
s'aligne sur ceux de x - 1
, ce qui entraîne le bitwise AND pour donner 0. Et c’est comme cela que la réponse à une seule ligne mentionnée ci-dessus est exacte.
Nous avons donc une propriété à notre disposition maintenant:
Lorsque nous soustrayons 1 à n’importe quel nombre, dans la représentation binaire, le plus à droite 1 deviendra 0 et tous les zéros précédant celui-ci deviendra maintenant 1
Une utilisation géniale de cette propriété est de découvrir - Combien de 1 sont présents dans la représentation binaire d'un nombre donné? Le code court et simple permettant de le faire pour un entier donné x
est :
byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);
Un autre aspect des nombres qui peut être prouvé à partir du concept expliqué ci-dessus est "Tout nombre positif peut-il être représenté par la somme des puissances de 2?".
Oui, chaque nombre positif peut être représenté par la somme des puissances de 2. Pour tout nombre, prenons sa représentation binaire. Ex: Numéro de prise 117
.
The binary representation of 117 is 1110101
Because 1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have 117 = 64 + 32 + 16 + 0 + 4 + 0 + 1
Après avoir posté la question, j'ai pensé à la solution suivante:
Nous devons vérifier si l'un des chiffres binaires est exactement un. Donc, nous déplaçons simplement le nombre d'un chiffre à l'autre et retournons true
s'il est égal à 1. Si nous venons d'un nombre impair ((number & 1) == 1
), nous savons que le résultat est false
. Cela s'est avéré (à l'aide d'un repère) légèrement plus rapide que la méthode d'origine pour les valeurs (grandes) vraies et beaucoup plus rapide pour les valeurs fausses ou petites.
private static bool IsPowerOfTwo(ulong number)
{
while (number != 0)
{
if (number == 1)
return true;
if ((number & 1) == 1)
// number is an odd number and not 1 - so it's not a power of two.
return false;
number = number >> 1;
}
return false;
}
Bien sûr, la solution de Greg est bien meilleure.
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
return ((x != 0) && !(x & (x - 1)));
Si x
est une puissance de deux, son seul bit 1 est en position n
. Cela signifie que x – 1
a un 0 en position n
. Pour voir pourquoi, rappelez-vous comment fonctionne une soustraction binaire. En soustrayant 1 de x
, l’emprunt se propage jusqu’à la position n
; le bit n
devient 0 et tous les bits inférieurs deviennent 1. Maintenant, puisque x
n'a pas de bit 1 en commun avec x – 1
, x & (x – 1)
vaut 0 et !(x & (x – 1))
est vrai.
int isPowerOfTwo(unsigned int x)
{
return ((x != 0) && ((x & (~x + 1)) == x));
}
C'est vraiment rapide. Il faut environ 6 minutes et 43 secondes pour vérifier tous les 2 ^ 32 entiers.
bool isPowerOfTwo(int x_)
{
register int bitpos, bitpos2;
asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
return bitpos > 0 && bitpos == bitpos2;
}
Trouvez si le nombre donné est une puissance de 2.
#include <math.h>
int main(void)
{
int n,logval,powval;
printf("Enter a number to find whether it is s power of 2\n");
scanf("%d",&n);
logval=log(n)/log(2);
powval=pow(2,logval);
if(powval==n)
printf("The number is a power of 2");
else
printf("The number is not a power of 2");
getch();
return 0;
}
Voici une autre méthode que j'ai conçue, dans ce cas, en utilisant |
au lieu de &
:
bool is_power_of_2(ulong x) {
if(x == (1 << (sizeof(ulong)*8 -1) ) return true;
return (x > 0) && (x<<1 == (x|(x-1)) +1));
}
Un nombre est une puissance de 2 s'il ne contient qu'un bit défini. Nous pouvons utiliser cette propriété et la fonction générique countSetBits
pour déterminer si un nombre correspond à une puissance de 2 ou non.
Ceci est un programme C++:
int countSetBits(int n)
{
int c = 0;
while(n)
{
c += 1;
n = n & (n-1);
}
return c;
}
bool isPowerOfTwo(int n)
{
return (countSetBits(n)==1);
}
int main()
{
int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
return 0;
}
Nous n'avons pas besoin de vérifier explicitement que 0 soit une puissance de 2, car elle renvoie False pour 0 également.
SORTIE
Num:0 Set Bits:0 is power of two: 0
Num:1 Set Bits:1 is power of two: 1
Num:2 Set Bits:1 is power of two: 1
Num:3 Set Bits:2 is power of two: 0
Num:4 Set Bits:1 is power of two: 1
Num:5 Set Bits:2 is power of two: 0
Num:15 Set Bits:4 is power of two: 0
Num:16 Set Bits:1 is power of two: 1
Num:22 Set Bits:3 is power of two: 0
Num:32 Set Bits:1 is power of two: 1
Num:38 Set Bits:3 is power of two: 0
Num:64 Set Bits:1 is power of two: 1
Num:70 Set Bits:3 is power of two: 0
pour toute puissance de 2, ce qui suit est également valable.
REMARQUE: échoue pour n = 0, vous devez donc le vérifier.
La raison pour laquelle cela fonctionne est:
- n est le complément à 2 de n. -n aura tous les bits situés à gauche du bit défini le plus à droite de n retourné par rapport à n. Pour une puissance de 2, il n'y a qu'un seul bit défini.
Amélioration de la réponse de @ user134548, sans arithmétique des bits:
public static bool IsPowerOfTwo(ulong n)
{
if (n % 2 != 0) return false; // is odd (can't be power of 2)
double exp = Math.Log(n, 2);
if (exp != Math.Floor(exp)) return false; // if exp is not integer, n can't be power
return Math.Pow(2, exp) == n;
}
Cela fonctionne bien pour:
IsPowerOfTwo(9223372036854775809)
Exemple
0000 0001 Yes
0001 0001 No
algorithme
En utilisant un masque de bits, divisez NUM
la variable en binaire
IF R > 0 AND L > 0: Return FALSE
Sinon, NUM
devient celui qui est non nul
IF NUM = 1: Return TRUE
Sinon, passez à l'étape 1
Complexité
Time ~ O(log(d))
où d
est le nombre de chiffres binaires
Ce programme dans Java renvoie "true" si number est une puissance de 2 et renvoie "false" s'il ne s'agit pas d'une puissance de 2
// To check if the given number is power of 2
import Java.util.Scanner;
public class PowerOfTwo {
int n;
void solve() {
while(true) {
// To eleminate the odd numbers
if((n%2)!= 0){
System.out.println("false");
break;
}
// Tracing the number back till 2
n = n/2;
// 2/2 gives one so condition should be 1
if(n == 1) {
System.out.println("true");
break;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
PowerOfTwo obj = new PowerOfTwo();
obj.n = in.nextInt();
obj.solve();
}
}
OUTPUT :
34
false
16
true
private static bool IsPowerOfTwo(ulong x)
{
var l = Math.Log(x, 2);
return (l == Math.Floor(l));
}
retourne i> 0 && (i ^ -i (-i << 1);) ==
Je n'ai pas trouvé une telle réponse. Que ce soit le mien