Si j'ai un nombre entier n
, comment puis-je trouver le numéro suivant k > n
tel que k = 2^i
, avec un élément i
de N
par décalage binaire ou logique.
Exemple: si j'ai n = 123
, Comment puis-je trouver k = 128
, qui est une puissance de deux, et non 124
qui n'est divisible que par deux. Cela devrait être simple, mais cela m'échappe.
Pour les entiers 32 bits, il s'agit d'un itinéraire simple et direct:
unsigned int n;
n--;
n |= n >> 1; // Divide by 2^k for consecutive doublings of k up to 32,
n |= n >> 2; // and then or the results.
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++; // The result is a number of 1 bits equal to the number
// of bits in the original number, plus 1. That's the
// next highest power of 2.
Voici un exemple plus concret. Prenons le nombre 221, qui est 11011101 en binaire:
n--; // 1101 1101 --> 1101 1100
n |= n >> 1; // 1101 1100 | 0110 1110 = 1111 1110
n |= n >> 2; // 1111 1110 | 0011 1111 = 1111 1111
n |= n >> 4; // ...
n |= n >> 8;
n |= n >> 16; // 1111 1111 | 1111 1111 = 1111 1111
n++; // 1111 1111 --> 1 0000 0000
Il y a un bit en neuvième position, ce qui représente 2 ^ 8, ou 256, qui est en effet la deuxième puissance la plus importante de 2. Chacun des décalages chevauche tous les 1 bits existants du nombre avec certains des zéros précédemment intacts, produisant finalement un nombre de 1 bits égal au nombre de bits du nombre d'origine. Ajouter un à cette valeur produit un nouveau pouvoir de 2.
Un autre exemple; nous utiliserons 131, qui est 10000011 en binaire:
n--; // 1000 0011 --> 1000 0010
n |= n >> 1; // 1000 0010 | 0100 0001 = 1100 0011
n |= n >> 2; // 1100 0011 | 0011 0000 = 1111 0011
n |= n >> 4; // 1111 0011 | 0000 1111 = 1111 1111
n |= n >> 8; // ... (At this point all bits are 1, so further bitwise-or
n |= n >> 16; // operations produce no effect.)
n++; // 1111 1111 --> 1 0000 0000
Et en effet, 256 est la deuxième puissance la plus élevée de 2 sur 131.
Si le nombre de bits utilisés pour représenter l'entier est lui-même une puissance de 2, vous pouvez continuer à étendre cette technique efficacement et indéfiniment (par exemple, ajoutez un n >> 32
ligne pour les entiers 64 bits).
Il existe en fait une solution d'assemblage pour cela (depuis le jeu d'instructions 80386).
Vous pouvez utiliser l'instruction BSR (Bit Scan Reverse) pour rechercher le bit le plus significatif de votre entier.
bsr scanne les bits, en commençant par le bit le plus significatif, dans l'opérande double mot ou le deuxième mot. Si les bits sont tous nuls, ZF est effacé. Sinon, ZF est défini et l'index de bit du premier bit défini trouvé, pendant le balayage dans le sens inverse, est chargé dans le registre de destination
(Extrait de: http://dlc.Sun.com/pdf/802-1948/802-1948.pdf )
Et puis augmenter le résultat avec 1.
donc:
bsr ecx, eax //eax = number
jz @zero
mov eax, 2 // result set the second bit (instead of a inc ecx)
shl eax, ecx // and move it ecx times to the left
ret // result is in eax
@zero:
xor eax, eax
ret
Dans les CPU plus récents, vous pouvez utiliser l'instruction lzcnt
beaucoup plus rapide (aka rep bsr
). lzcnt
fait son travail en un seul cycle.
Une manière plus mathématique, sans boucles:
public static int ByLogs(int n)
{
double y = Math.Floor(Math.Log(n, 2));
return (int)Math.Pow(2, y + 1);
}
Voici une réponse logique:
function getK(int n)
{
int k = 1;
while (k < n)
k *= 2;
return k;
}
Voici la réponse de John Feminella implémentée en boucle afin qu'il puisse gérer les longs entiers de Python :
def next_power_of_2(n):
"""
Return next power of 2 greater than or equal to n
"""
n -= 1 # greater than OR EQUAL TO n
shift = 1
while (n+1) & n: # n+1 is not a power of 2 yet
n |= n >> shift
shift <<= 1
return n + 1
Il revient également plus rapidement si n est déjà une puissance de 2.
Pour Python> 2.7, c'est plus simple et plus rapide pour la plupart des N:
def next_power_of_2(n):
"""
Return next power of 2 greater than or equal to n
"""
return 2**(n-1).bit_length()
Voici un joker qui n'a pas de boucles, mais utilise un flotteur intermédiaire.
// compute k = nextpowerof2(n)
if (n > 1)
{
float f = (float) n;
unsigned int const t = 1U << ((*(unsigned int *)&f >> 23) - 0x7f);
k = t << (t < n);
}
else k = 1;
Ceci, ainsi que de nombreux autres hacks bidirectionnels, y compris celui soumis par John Feminella, peuvent être trouvés ici .
Les extraits suivants sont pour le nombre suivant k> n tel que k = 2 ^ i
(n = 123 => k = 128, n = 128 => k = 256) comme spécifié par OP.
Si vous voulez que la puissance la plus petite de 2 soit supérieure à OR égale à n , remplacez simplement __builtin_clzll(n)
par __builtin_clzll(n-1)
dans les extraits ci-dessus.
constexpr uint64_t nextPowerOfTwo64 (uint64_t n)
{
return 1ULL << (sizeof(uint64_t) * 8 - __builtin_clzll(n));
}
CHAR_BIT
comme proposé par martinec#include <cstdint>
constexpr uint64_t nextPowerOfTwo64 (uint64_t n)
{
return 1ULL << (sizeof(uint64_t) * CHAR_BIT - __builtin_clzll(n));
}
#include <cstdint>
template <typename T>
constexpr T nextPowerOfTwo64 (T n)
{
T clz = 0;
if constexpr (sizeof(T) <= 32)
clz = __builtin_clzl(n); // unsigned long
else if (sizeof(T) <= 64)
clz = __builtin_clzll(n); // unsigned long long
else { // See https://stackoverflow.com/a/40528716
uint64_t hi = n >> 64;
uint64_t lo = (hi == 0) ? n : -1ULL;
clz = _lzcnt_u64(hi) + _lzcnt_u64(lo);
}
return T{1} << (CHAR_BIT * sizeof(T) - clz);
}
Si vous utilisez un compilateur autre que GCC ou Clang, veuillez visiter la page Wikipedia répertoriant les nombre de zéros non significatifs fonctions au niveau du bit :
__builtin_clzl()
par _BitScanForward()
__builtin_clzl()
par __lzcnt()
__builtin_clzl()
par _bit_scan_forward
__builtin_clzl()
par countLeadingZeros()
Veuillez proposer des améliorations dans les commentaires. Proposez également une alternative pour le compilateur que vous utilisez, ou votre langage de programmation ...
supposons que x n'est pas négatif.
int pot = Integer.highestOneBit(x);
if (pot != x) {
pot *= 2;
}
Si vous utilisez GCC, MinGW ou Clang:
template <typename T>
T nextPow2(T in)
{
return (in & (T)(in - 1)) ? (1U << (sizeof(T) * 8 - __builtin_clz(in))) : in;
}
Si vous utilisez Microsoft Visual C++, utilisez la fonction _BitScanForward()
pour remplacer __builtin_clz()
.
function Pow2Thing(int n)
{
x = 1;
while (n>0)
{
n/=2;
x*=2;
}
return x;
}
Bit-twiddling, vous dites?
long int pow_2_ceil(long int t) {
if (t == 0) return 1;
if (t != (t & -t)) {
do {
t -= t & -t;
} while (t != (t & -t));
t <<= 1;
}
return t;
}
Chaque boucle supprime directement le bit le moins significatif. N.B. Cela ne fonctionne que lorsque les numéros signés sont codés en complément à deux.
private static int nextHighestPower(int number){
if((number & number-1)==0){
return number;
}
else{
int count=0;
while(number!=0){
number=number>>1;
count++;
}
return 1<<count;
}
}
Et quelque chose comme ça:
int pot = 1;
for (int i = 0; i < 31; i++, pot <<= 1)
if (pot >= x)
break;
Oublie ça! Il utilise la boucle!
unsigned int nextPowerOf2 ( unsigned int u)
{
unsigned int v = 0x80000000; // supposed 32-bit unsigned int
if (u < v) {
while (v > u) v = v >> 1;
}
return (v << 1); // return 0 if number is too big
}
Il vous suffit de trouver le bit le plus significatif et de le déplacer vers la gauche une fois. Voici une implémentation Python. Je pense que x86 a une instruction pour obtenir le MSB, mais ici je l'implémente en Python direct. Une fois que vous avez le MSB, c'est facile.
>>> def msb(n):
... result = -1
... index = 0
... while n:
... bit = 1 << index
... if bit & n:
... result = index
... n &= ~bit
... index += 1
... return result
...
>>> def next_pow(n):
... return 1 << (msb(n) + 1)
...
>>> next_pow(1)
2
>>> next_pow(2)
4
>>> next_pow(3)
4
>>> next_pow(4)
8
>>> next_pow(123)
128
>>> next_pow(222)
256
>>>