web-dev-qa-db-fra.com

Quel est le moyen le plus simple de tester si un nombre est une puissance de 2 en C++?

J'ai besoin d'une fonction comme celle-ci:

// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true  is_power_of_2(3) => false
bool is_power_of_2(int n);

Quelqu'un peut-il suggérer comment je pourrais écrire ceci? Pouvez-vous me dire un bon site web où ce type d'algorithme peut être trouvé?

72
Ant

(n & (n - 1)) == 0 est le meilleur. Cependant, notez qu'il renverra incorrectement la valeur true pour n = 0; par conséquent, si cela est possible, vous souhaiterez le vérifier explicitement.

http://www.graphics.stanford.edu/~seander/bithacks.html possède une vaste collection d’algorithmes intelligents, notamment celui-ci.

156
Anonymous

Une puissance de deux n'aura qu'un bit défini (pour les nombres non signés). Quelque chose comme

bool powerOfTwo = !(x == 0) && !(x & (x - 1));

Fonctionnera bien; un de moins qu'une puissance de deux correspond à tous les 1 dans les bits les moins significatifs; il en va donc de même pour AND à 0 bits.

Comme je supposais des nombres non signés, le test == 0 (que j'avais initialement oublié, désolé) est adéquat. Vous voudrez peut-être un test> 0 si vous utilisez des entiers signés.

72
Adam Wright

Les puissances de deux en binaire ressemblent à ceci:

1: 0001
2: 0010
4: 0100
8: 1000

Notez qu'il y a toujours exactement 1 bit défini. La seule exception est avec un entier signé. par exemple. Un entier signé de 8 bits avec une valeur de -128 se présente comme suit:

10000000

Ainsi, après avoir vérifié que le nombre est supérieur à zéro, nous pouvons utiliser un petit bidouillage astucieux pour vérifier qu'un seul bit est activé.

bool is_power_of_2(int x) {
    return x > 0 && !(x & (x−1));
}

Pour plus de bricolage, voir ici .

44
Matt Howells

Approche n ° 1:

Divisez le nombre par 2 de manière reclus pour le vérifier.

Complexité temporelle: O (log2n).

Approche n ° 2:

Au niveau des bits ET le nombre avec son numéro juste précédent doit être égal à ZERO.

Exemple: Nombre = 8 Binaire de 8: 1 0 0 0 Binaire de 7: 0 1 1 1 et le AND au niveau des bits des deux nombres est 0 0 0 0 = 0.

Complexité temporelle: O (1).

Approche n ° 3:

Au niveau du bit XOR, le nombre avec son numéro juste précédent doit être la somme des deux nombres.

Exemple: Nombre = 8 Binaire de 8: 1 0 0 0 Binaire de 7: 0 1 1 1 et le bitwise XOR des deux nombres est 1 1 1 1 1 = 15 .

Complexité temporelle: O (1).

http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html

12
Raj Dixit
bool is_power_of_2(int i) {
    if ( i <= 0 ) {
        return 0;
    }
    return ! (i & (i-1));
}
5
Rob Wells

pour toute puissance de 2, ce qui suit est également valable.

n & (- n) == n

NOTE: La condition est vraie pour n = 0, bien que ce ne soit pas une puissance de 2 .
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 des puissances de 2, il n'y a qu'un seul bit défini.

3
FReeze FRancis
return n > 0 && 0 == (1 << 30) % n;
3
Yuxiang Zhang

Quel est le moyen le plus simple de tester si un nombre est une puissance de 2 en C++?

Si vous avez un processeur Intel moderne avec Instructions de manipulation de bits , vous pouvez alors procéder comme suit. Il omet le code simple C/C++ car d’autres y ont déjà répondu, mais vous en avez besoin si l’IMC n’est pas disponible ou activé.

bool IsPowerOf2_32(uint32_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
    return !!((x > 0) && _blsr_u32(x));
#endif
    // Fallback to C/C++ code
}

bool IsPowerOf2_64(uint64_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
    return !!((x > 0) && _blsr_u64(x));
#endif
    // Fallback to C/C++ code
}

GCC, ICC et Clang signalent la prise en charge de BMI avec __BMI__. Il est disponible dans les compilateurs Microsoft dans Visual Studio 2015 et versions ultérieures lorsque/ AVX2 est disponible et activé . Pour les en-têtes dont vous avez besoin, voir Fichiers d’en-tête pour les composants intrinsèques SIMD .

Je garde habituellement le _blsr_u64 avec un _LP64_ en cas de compilation sur i686. Clang nécessite un peu de solution de contournement, car il utilise un nom de symbole intrinsèque légèrement différent:

#if defined(__GNUC__) && defined(__BMI__)
# if defined(__clang__)
#  ifndef _tzcnt_u32
#   define _tzcnt_u32(x) __tzcnt_u32(x)
#  endif
#  ifndef _blsr_u32
#    define  _blsr_u32(x)  __blsr_u32(x)
#  endif
#  ifdef __x86_64__
#   ifndef _tzcnt_u64
#    define _tzcnt_u64(x) __tzcnt_u64(x)
#   endif
#   ifndef _blsr_u64
#     define  _blsr_u64(x)  __blsr_u64(x)
#   endif
#  endif  // x86_64
# endif  // Clang
#endif  // GNUC and BMI

Pouvez-vous me dire un bon site web où ce type d'algorithme peut être trouvé?

Ce site Web est souvent cité: Bit Twiddling Hacks .

2
jww

Suivre serait plus rapide que la réponse la plus favorable en raison du court-circuitage booléen et du fait que la comparaison est lente.

int isPowerOfTwo(unsigned int x)
{
  return x && !(x & (x – 1));
}

Si vous savez que x ne peut pas être 0 alors 

int isPowerOfTwo(unsigned int x)
{
  return !(x & (x – 1));
}
2
Margus

En C++ 20, il existe std::ispow2 que vous pouvez utiliser exactement à cette fin si vous n'avez pas besoin de l'implémenter vous-même:

_#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));
_
2
Rakete1111

Ce n'est pas le moyen le plus rapide ou le plus rapide, mais je pense que c'est très lisible. Donc je ferais quelque chose comme ça:

bool is_power_of_2(int n)
  int bitCounter=0;
  while(n) {
    if ((n & 1) == 1) {
      ++bitCounter;
    }
    n >>= 1;
  }
  return (bitCounter == 1);
}

Cela fonctionne car le binaire est basé sur des puissances de deux. Tout nombre avec un seul bit défini doit être une puissance de deux.

1
Jere.Jones

C'est le plus rapide:

if(1==__builtin_popcount(n))
1
F10PPY

Voici une autre méthode, dans ce cas, utilisez | au lieu de &:

bool is_power_of_2(int x) {
    return x > 0 && (x<<1 == (x|(x-1)) +1));
}
0
Chethan

C'est possible avec c ++

int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}
0
Jay Ponkia