Arredondando para a próxima potência de 2


189

Quero escrever uma função que retorne a próxima potência mais próxima de 2 números. Por exemplo, se minha entrada for 789, a saída deve ser 1024. Existe alguma maneira de conseguir isso sem usar loops, mas apenas usando alguns operadores bit a bit?



4
Como esclarecimento, você precisa da potência mais próxima de 2 (ou seja, 65 daria a você 64, mas 100 daria a você 128) ou a mais próxima acima (ou seja, 65 daria a você 128 e 100)?
— 22611 Kim Reece

1
São várias perguntas correspondentes a esta. Por exemplo: stackoverflow.com/questions/364985/…
— Yann Droneaud


7
@ Nathan O seu link é 8 meses depois desta pergunta.
— Joseph Quinsey

Respostas:


148

Verifique os Bit Twiddling Hacks . Você precisa obter o logaritmo da base 2 e adicionar 1 a isso. Exemplo para um valor de 32 bits:

Arredonde para a próxima potência mais alta de 2

unsigned int v; // compute the next highest power of 2 of 32-bit v

v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;

A extensão para outras larguras deve ser óbvia.


11
Esta não é a solução mais eficiente, porque muitos processadores possuem instruções especiais para contar zeros à esquerda, que podem ser usados ​​para calcular log2 com muita eficiência. Veja en.wikipedia.org/wiki/Find_first_set
— Simon

7
@ Simon: é a solução portátil. Não há nenhum algoritmo eficiente comum para todas as arquiteturas
— phuclv

5
E se o número em si for uma potência de dois?
— Litherum

5
Este tópico ainda está bem referenciado, mas esta resposta (e a maioria dos outros) está altamente desatualizada. As CPUs têm uma instrução para ajudar nisso (na verdade já naquela época?). De: jameshfisher.com/2018/03/30/round-up-power-2.html uint64_t next_pow2(uint64_t x) { return x == 1 ? 1 : 1<<(64-__builtin_clzl(x-1)); } E por 32 bits: uint32_t next_pow2(uint32_t x) { return x == 1 ? 1 : 1<<(32-__builtin_clz(x-1)); }isto é, se você usar o GCC (e Clang, eu acho?), Mas seria aconselhável reservar um tempo para encontre a chamada para o CLZ em vez de copiar e colar todas as opções existentes.
— MappaM 13/03/19

2
@MappaM Esta resposta ainda é altamente relevante e a melhor maneira portátil de fazer isso. Sua versão de 64 bits possui um comportamento indefinido se x > UINT32_MAXnão é sem ramo. Além disso, o GCC e o Clang usam -mtune=genericpor padrão (como a maioria das distros), portanto seu código NÃO será expandido para as lzcntinstruções em x86_64 - ele será expandido para algo MUITO mais lento (uma rotina libgcc), a menos que você use algo parecido -march=native. Portanto, a substituição proposta é não portátil, com bugs e (normalmente) mais lenta.
— Craig Barnes

76
next = pow(2, ceil(log(x)/log(2)));

Isso funciona ao encontrar o número pelo qual você aumentaria 2 para obter x (pegue o log do número e divida pelo log da base desejada, consulte a Wikipedia para mais informações ). Em seguida, arredonde isso para cima para obter a potência numérica inteira mais próxima.

Este é um método de propósito mais geral (ou seja, mais lento!) Do que os métodos bit a bit vinculados em outros lugares, mas é bom saber matemática, não é?


3
No C99, você também pode usar o log2, se suportado por suas ferramentas. O GCC e o VS não parecem :(
— Mateus Leia

2
Está faltando um suporte ... next = pow (2, ceil (log (x) / log (2)));
— Matthieu Cormier

13
Tenha cuidado com a precisão da bóia, no entanto. log(pow(2,29))/log(2)= 29.000000000000004, então o resultado é 2 30 em vez de retornar 2 29. Acho que é por isso que as funções log2 existem?
— endolith 9/12/13

48
O custo disso é provavelmente de pelo menos 200 ciclos e nem está correto. Por que isso tem tantos votos positivos?
— Axel Gneiting

4
@SuperflyJon Mas ele menciona operadores bit a bit e presumo que a correção esteja implícita em qualquer pergunta, a menos que indicado de outra forma.
— BlackJack

50
unsigned long upper_power_of_two(unsigned long v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v;

}

62
Seria bom se você o atribuísse (a menos que você o descobrisse). Ele vem da página de hackers que rodam um pouco.
— florin 21/01

3
Isso é para um número de 32 bits? Extensão para 64 bits?
— Jonathan Leffler

Jonathan, você precisa fazer isso na metade superior e, se isso for zero, você faz na metade inferior.
— florin 21/01

5
@florin, se v é do tipo de 64 bits, você não pode simplesmente adicionar um "c | = v >> 32" após o de 16?
— Evan Teran

3
O código que funciona apenas para uma largura de bit específica deve estar usando tipos de largura fixa em vez de tipos de largura mínima. Esta função deve receber e retornar a uint32_t.
— Craig Barnes

50

Eu acho que isso funciona também:

int power = 1;
while(power < x)
    power*=2;

E a resposta é power.


19
É justo que a pergunta não tenha laços. Mas, por mais inteligentes que sejam algumas das outras funções, para o código que não é sensível ao desempenho, a resposta que é rápida e facilmente compreendida e verificada como correta sempre ganha para mim.
— Tim MB

2
Isso não está retornando o poder mais próximo de 2, butthe poder de que é imediatamente maior do que X. Ainda muito bom
— CoffeDeveloper

1
Em vez de se multiplicar, alguns bit a bit "mágica" pode ser usado em vezpower <<= 1
— Vallentin

5
@ Vallentin Isso deve ser otimizado automaticamente por um compilador.
— MarkWeston #

4
Cuidado com o loop infinito se xfor muito grande (ou seja, bits insuficientes para representar a próxima potência de 2).
— Alban

36

Se você estiver usando o GCC, consulte Otimizando a função next_pow2 () da Lockless Inc. Esta página descreve uma maneira de usar a função interna builtin_clz()(conte o zero à esquerda) e, posteriormente, use diretamente x86 (ia32) instrução assembler bsr(inversa bit scan), tal como é descrito em outra resposta 's link para o site gamedev . Esse código pode ser mais rápido do que os descritos na resposta anterior .

A propósito, se você não usar as instruções do assembler e o tipo de dados de 64 bits, poderá usar este

/**
 * return the smallest power of two value
 * greater than x
 *
 * Input range:  [2..2147483648]
 * Output range: [2..2147483648]
 *
 */
__attribute__ ((const))
static inline uint32_t p2(uint32_t x)
{
#if 0
    assert(x > 1);
    assert(x <= ((UINT32_MAX/2) + 1));
#endif

    return 1 << (32 - __builtin_clz (x - 1));
}

3
Observe que isso retorna a menor potência de 2 maior que OR igual a x. Alterar (x -1) para x altera a função para retornar a potência menor de 2 maior que x.
— Guillaume

2
Você pode usar _BitScanForwardno Visual C ++
— KindDragon

Você também pode usar__builtin_ctz()
— MarkP 31/03

@MarkP __builtin_ctz()não será útil para arredondar qualquer poder não de 2 número até a próxima potência de dois
— Yann Droneaud

2
Adicione na sua resposta um link para a lista da Wikipedia de funções bit a bit internas para outros compiladores: en.wikipedia.org/wiki/Find_first_set#Tool_and_library_support                                Forneça também uma versão de 64 bits. Eu proponho a seguinte função C ++ 11:              constexpr uint64_t nextPowerOfTwo64 (uint64_t x) { return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x)); }
— olibre

15

Mais uma, embora eu use ciclo, mas isso é muito mais rápido que os operandos matemáticos

potência de duas opções de "andar":

int power = 1;
while (x >>= 1) power <<= 1;

potência da opção de dois "ceil":

int power = 2;
x--;    // <<-- UPDATED
while (x >>= 1) power <<= 1;

ATUALIZAR

Como mencionado nos comentários, houve um erro no local ceilonde o resultado foi errado.

Aqui estão as funções completas:

unsigned power_floor(unsigned x) {
    int power = 1;
    while (x >>= 1) power <<= 1;
    return power;
}

unsigned power_ceil(unsigned x) {
    if (x <= 1) return 1;
    int power = 2;
    x--;
    while (x >>= 1) power <<= 1;
    return power;
}

2
o resultado não está correto se a xpotência é 2. É necessário um micro para testar se a entrada é a potência 2. #define ISPOW2(x) ((x) > 0 && !((x) & (x-1)))
— pgplus1628

@zorksylar seria mais eficientementeif (x == 0) return 1; /* Or 0 (Which is what I use) */ x--; /* Rest of program */
— yyny 31/03

Boa solução! mas o power of two "ceil" optionnão está correto. Por exemplo, quando x = 2o resultado deve ser em 2vez de4
— MZD

10

Para qualquer tipo não assinado, com base nos Bit Twiddling Hacks:

#include <climits>
#include <type_traits>

template <typename UnsignedType>
UnsignedType round_up_to_power_of_2(UnsignedType v) {
  static_assert(std::is_unsigned<UnsignedType>::value, "Only works for unsigned types");
  v--;
  for (size_t i = 1; i < sizeof(v) * CHAR_BIT; i *= 2) //Prefer size_t "Warning comparison between signed and unsigned integer"
  {
    v |= v >> i;
  }
  return ++v;
}

Não há realmente um loop lá, pois o compilador sabe em tempo de compilação o número de iterações.


4
Note-se que a pergunta é sobre C.
— martinkunev

@martinkunev Basta substituir o UnsignedType e processá-lo manualmente. Tenho certeza de que um programador em C pode expandir esse modelo simples, ignorando a std::is_unsigned<UnsignedType>::valueafirmação.
— precisa saber é o seguinte

2
@ user877329 Claro, seria bom ter uma resposta em Javascript, assim, apenas no caso de alguém quiser traduzir isso para C.
— martinkunev

@martinkunev UnsignedType em JavaScript? De qualquer forma, esta solução mostra como fazer isso para qualquer UnsignedType e, por acaso, é escrita em C ++, em vez de pseudocódigo [sizeof (v) * CHAR_BIT em vez de algo como o número de bits em um objeto de UnsignedType].
— precisa saber é o seguinte

9

Para carros alegóricos IEEE, você seria capaz de fazer algo assim.

int next_power_of_two(float a_F){
    int f = *(int*)&a_F;
    int b = f << 9 != 0; // If we're a power of two this is 0, otherwise this is 1

    f >>= 23; // remove factional part of floating point number
    f -= 127; // subtract 127 (the bias) from the exponent

    // adds one to the exponent if were not a power of two, 
    // then raises our new exponent to the power of two again.
    return (1 << (f + b)); 
}

Se você precisar de uma solução inteira e conseguir usar a montagem em linha, o BSR fornecerá o log2 de um número inteiro no x86. Ele conta quantos bits corretos estão configurados, o que é exatamente igual ao log2 desse número. Outros processadores têm instruções semelhantes (geralmente), como CLZ e, dependendo do seu compilador, pode haver um intrínseco disponível para fazer o trabalho por você.


Este é um interessante eventhough não relacionados à pergunta (eu quero arredondamento apenas números inteiros), vai experimentar este ..
— Naveen

Surgiu depois de ler o artigo da wikipedia sobre carros alegóricos. Além disso, usei-o para calcular raízes quadradas em precisão inteira. Também legal, mas ainda mais independente.
— Jasper Bekkers

Isso quebra as regras estritas de alias. Em alguns compiladores, pode não funcionar ou emitir um aviso.
— martinkunev


5
/*
** http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
*/
#define __LOG2A(s) ((s &0xffffffff00000000) ? (32 +__LOG2B(s >>32)): (__LOG2B(s)))
#define __LOG2B(s) ((s &0xffff0000)         ? (16 +__LOG2C(s >>16)): (__LOG2C(s)))
#define __LOG2C(s) ((s &0xff00)             ? (8  +__LOG2D(s >>8)) : (__LOG2D(s)))
#define __LOG2D(s) ((s &0xf0)               ? (4  +__LOG2E(s >>4)) : (__LOG2E(s)))
#define __LOG2E(s) ((s &0xc)                ? (2  +__LOG2F(s >>2)) : (__LOG2F(s)))
#define __LOG2F(s) ((s &0x2)                ? (1)                  : (0))

#define LOG2_UINT64 __LOG2A
#define LOG2_UINT32 __LOG2B
#define LOG2_UINT16 __LOG2C
#define LOG2_UINT8  __LOG2D

static inline uint64_t
next_power_of_2(uint64_t i)
{
#if defined(__GNUC__)
    return 1UL <<(1 +(63 -__builtin_clzl(i -1)));
#else
    i =i -1;
    i =LOG2_UINT64(i);
    return 1UL <<(1 +i);
#endif
}

Se você não deseja se aventurar no domínio do comportamento indefinido, o valor da entrada deve estar entre 1 e 2 ^ 63. A macro também é útil para definir constante no tempo de compilação.


Essa é provavelmente a pior solução (também está faltando o sufixo ULL na constante de 64 bits). Isso gerará 32 testes por entrada em todos os casos. Melhor usar um loop while, sempre será mais rápido ou na mesma velocidade.
— precisa saber é o seguinte

1
MAS ... isso pode ser avaliado pelo pré-processador se a entrada for uma constante e, portanto, ZERO operação em tempo de execução!
— Michael

4

Para completar, aqui está uma implementação de ponto flutuante no padrão pântano C.

double next_power_of_two(double value) {
    int exp;
    if(frexp(value, &exp) == 0.5) {
        // Omit this case to round precise powers of two up to the *next* power
        return value;
    }
    return ldexp(1.0, exp);
}

1
Navegadores aleatórios, se você ler este comentário, escolha este código. Essa é claramente a melhor resposta, sem instruções especiais, sem modificações, apenas código eficiente, portátil e padrão. Adivinhando por que ninguém mais votou positivamente ^^
— CoffeDeveloper

5
Navegadores aleatórios, isso será muito lento se você não tiver hardware especializado de ponto flutuante. No x86, você pode executar círculos em torno desse código usando a manipulação de bits. rep bsr ecx,eax; mov eax,0; cmovnz eax,2; shl eax,clé cerca de 25x mais rápido.
— 31416 Johan Johan

4

Uma solução específica eficiente da Microsoft (por exemplo, Visual Studio 2017) em C / C ++ para entrada inteira. Manipula o caso da entrada que corresponde exatamente a uma potência de dois valores, decrementando antes de verificar a localização do 1 bit mais significativo.

inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
    unsigned long Index;
    _BitScanReverse(&Index, Value - 1);
    return (1U << (Index + 1));
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#if defined(WIN64) // The _BitScanReverse64 intrinsic is only available for 64 bit builds because it depends on x64

inline unsigned long long ExpandToPowerOf2(unsigned long long Value)
{
    unsigned long Index;
    _BitScanReverse64(&Index, Value - 1);
    return (1ULL << (Index + 1));
}

#endif

Isso gera 5 ou mais instruções embutidas para um processador Intel semelhante ao seguinte:

dec eax
bsr rcx, rax
inc ecx
mov eax, 1
shl rax, cl

Aparentemente, o compilador do Visual Studio C ++ não é codificado para otimizar isso para valores em tempo de compilação, mas não é como se houvesse muitas instruções lá.

Editar:

Se você deseja que um valor de entrada 1 dê 1 (2 à potência zero), uma pequena modificação no código acima ainda gera instruções diretas, sem ramificação.

inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
    unsigned long Index;
    _BitScanReverse(&Index, --Value);
    if (Value == 0)
        Index = (unsigned long) -1;
    return (1U << (Index + 1));
}

Gera apenas mais algumas instruções. O truque é que o Index pode ser substituído por um teste seguido por uma instrução cmove.


Um pequeno erro: ele deve retornar 1 por 1, embora isso não ocorra.
— 0kcats

Obrigado. No aplicativo para o qual foi desenvolvido, precisávamos explicitamente de 2 para a primeira potência quando 1 é inserido. Eu poderia ser tomado como um caso especial com condicional sem gerar muitas instruções adicionais, imagino.
— NoelC

Atualizada a resposta para incluir uma versão que retorne 1 para um valor de entrada 1.
— #

3

No x86, você pode usar as instruções de manipulação do sse4 bit para torná-lo mais rápido.

//assume input is in eax
popcnt edx,eax
lzcnt ecx,eax
cmp edx,1
jle @done       //popcnt says its a power of 2, return input unchanged
mov eax,2
shl eax,cl
@done: rep ret

Em c, você pode usar as intrínsecas correspondentes.


Inútil, mas IMPRESSIONANTE!
— Marco

3

Aqui está a minha solução em C. Espero que isso ajude!

int next_power_of_two(int n) {
    int i = 0;
    for (--n; n > 0; n >>= 1) {
        i++;
    }
    return 1 << i;
}

0

Muitas arquiteturas de processador oferecem suporte log base 2ou operação muito semelhante - count leading zeros. Muitos compiladores têm intrínsecas para isso. Consulte https://en.wikipedia.org/wiki/Find_first_set


não se trata de encontrar o bit mais alto definido (= bsr) ou contar zeros à esquerda. ele deseja arredondar para a potência mais próxima de 2. a resposta com "subtrair 1, depois faça bsr e desloque 1 para a esquerda" faz isso.
— Flo

0

Supondo que você tenha um bom compilador e ele possa fazer um pouco de distorção antes da mão, isso está acima de mim neste momento, mas de qualquer maneira isso funciona !!!

    // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
    #define SH1(v)  ((v-1) | ((v-1) >> 1))            // accidently came up w/ this...
    #define SH2(v)  ((v) | ((v) >> 2))
    #define SH4(v)  ((v) | ((v) >> 4))
    #define SH8(v)  ((v) | ((v) >> 8))
    #define SH16(v) ((v) | ((v) >> 16))
    #define OP(v) (SH16(SH8(SH4(SH2(SH1(v))))))         

    #define CB0(v)   ((v) - (((v) >> 1) & 0x55555555))
    #define CB1(v)   (((v) & 0x33333333) + (((v) >> 2) & 0x33333333))
    #define CB2(v)   ((((v) + ((v) >> 4) & 0xF0F0F0F) * 0x1010101) >> 24)
    #define CBSET(v) (CB2(CB1(CB0((v)))))
    #define FLOG2(v) (CBSET(OP(v)))

Código de teste abaixo:

#include <iostream>

using namespace std;

// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
#define SH1(v)  ((v-1) | ((v-1) >> 1))  // accidently guess this...
#define SH2(v)  ((v) | ((v) >> 2))
#define SH4(v)  ((v) | ((v) >> 4))
#define SH8(v)  ((v) | ((v) >> 8))
#define SH16(v) ((v) | ((v) >> 16))
#define OP(v) (SH16(SH8(SH4(SH2(SH1(v))))))         

#define CB0(v)   ((v) - (((v) >> 1) & 0x55555555))
#define CB1(v)   (((v) & 0x33333333) + (((v) >> 2) & 0x33333333))
#define CB2(v)   ((((v) + ((v) >> 4) & 0xF0F0F0F) * 0x1010101) >> 24)
#define CBSET(v) (CB2(CB1(CB0((v)))))
#define FLOG2(v) (CBSET(OP(v))) 

#define SZ4         FLOG2(4)
#define SZ6         FLOG2(6)
#define SZ7         FLOG2(7)
#define SZ8         FLOG2(8) 
#define SZ9         FLOG2(9)
#define SZ16        FLOG2(16)
#define SZ17        FLOG2(17)
#define SZ127       FLOG2(127)
#define SZ1023      FLOG2(1023)
#define SZ1024      FLOG2(1024)
#define SZ2_17      FLOG2((1ul << 17))  // 
#define SZ_LOG2     FLOG2(SZ)

#define DBG_PRINT(x) do { std::printf("Line:%-4d" "  %10s = %-10d\n", __LINE__, #x, x); } while(0);

uint32_t arrTble[FLOG2(63)];

int main(){
    int8_t n;

    DBG_PRINT(SZ4);    
    DBG_PRINT(SZ6);    
    DBG_PRINT(SZ7);    
    DBG_PRINT(SZ8);    
    DBG_PRINT(SZ9); 
    DBG_PRINT(SZ16);
    DBG_PRINT(SZ17);
    DBG_PRINT(SZ127);
    DBG_PRINT(SZ1023);
    DBG_PRINT(SZ1024);
    DBG_PRINT(SZ2_17);

    return(0);
}

Saídas:

Line:39           SZ4 = 2
Line:40           SZ6 = 3
Line:41           SZ7 = 3
Line:42           SZ8 = 3
Line:43           SZ9 = 4
Line:44          SZ16 = 4
Line:45          SZ17 = 5
Line:46         SZ127 = 7
Line:47        SZ1023 = 10
Line:48        SZ1024 = 10
Line:49        SZ2_16 = 17

0

Estou tentando obter a potência mais baixa mais baixa de 2 e fiz essa função. Pode multiplicar o número mais baixo 2 vezes mais próximo para obter a potência superior mais próxima de 2

int nearest_upper_power(int number){
    int temp=number;
    while((number&(number-1))!=0){
        temp<<=1;
        number&=temp;
    }
    //Here number is closest lower power 
    number*=2;
    return number;
}

0

Resposta adaptada de Paul Dixon ao Excel, isso funciona perfeitamente.

 =POWER(2,CEILING.MATH(LOG(A1)/LOG(2)))

0

Uma variante da resposta @YannDroneaud válida para x==1, apenas para chapas x86, compiladores, gcc ou clang:

__attribute__ ((const))
static inline uint32_t p2(uint32_t x)
{
#if 0
    assert(x > 0);
    assert(x <= ((UINT32_MAX/2) + 1));
#endif
  int clz;
  uint32_t xm1 = x-1;
  asm(
    "lzcnt %1,%0"
    :"=r" (clz)
    :"rm" (xm1)
    :"cc"
    );
    return 1 << (32 - clz);
}

0

Aqui está o que estou usando para que essa seja uma expressão constante, se a entrada for uma expressão constante.

#define uptopow2_0(v) ((v) - 1)
#define uptopow2_1(v) (uptopow2_0(v) | uptopow2_0(v) >> 1)
#define uptopow2_2(v) (uptopow2_1(v) | uptopow2_1(v) >> 2)
#define uptopow2_3(v) (uptopow2_2(v) | uptopow2_2(v) >> 4)
#define uptopow2_4(v) (uptopow2_3(v) | uptopow2_3(v) >> 8)
#define uptopow2_5(v) (uptopow2_4(v) | uptopow2_4(v) >> 16)

#define uptopow2(v) (uptopow2_5(v) + 1)  /* this is the one programmer uses */

Por exemplo, uma expressão como:

uptopow2(sizeof (struct foo))

reduzirá muito bem a uma constante.


0

Você pode achar que o seguinte esclarecimento é útil para seu objetivo:


0

Converta-o em um flutuador e use .hex (), que mostra a representação IEEE normalizada.

>>> float(789).hex() '0x1.8a80000000000p+9'

Em seguida, basta extrair o expoente e adicionar 1.

>>> int(float(789).hex().split('p+')[1]) + 1 10

E aumente 2 para esse poder.

>>> 2 ** (int(float(789).hex().split('p+')[1]) + 1) 1024


Nota esta resposta está em python
— David Wallace

0
import sys


def is_power2(x):
    return x > 0 and ((x & (x - 1)) == 0)


def find_nearest_power2(x):
    if x <= 0:
        raise ValueError("invalid input")
    if is_power2(x):
        return x
    else:
        bits = get_bits(x)
        upper = 1 << (bits)
        lower = 1 << (bits - 1)
        mid = (upper + lower) // 2
        if (x - mid) > 0:
            return upper
        else:
            return lower


def get_bits(x):
    """return number of bits in binary representation"""
    if x < 0:
        raise ValueError("invalid input: input should be positive integer")
    count = 0
    while (x != 0):
        try:
            x = x >> 1
        except TypeError as error:
            print(error, "input should be of type integer")
            sys.exit(1)
        count += 1
    return count

-1

Se você precisar para coisas relacionadas ao OpenGL:

/* Compute the nearest power of 2 number that is 
 * less than or equal to the value passed in. 
 */
static GLuint 
nearestPower( GLuint value )
{
    int i = 1;

    if (value == 0) return -1;      /* Error! */
    for (;;) {
         if (value == 1) return i;
         else if (value == 3) return i*4;
         value >>= 1; i *= 2;
    }
}

8
'for' é um loop.
— florin 21/01

1
florin: é. e é usado como um loop aqui, não é?
— Tamas Czinege 21/01/09

9
DrJokepu - Eu acho que florin quis dizer aqui que o OP pediu uma solução loop-menos
— Eli Bendersky

-1

Se você deseja um modelo de uma linha. Aqui está

int nxt_po2(int n) { return 1 + (n|=(n|=(n|=(n|=(n|=(n-=1)>>1)>>2)>>4)>>8)>>16); }

ou

int nxt_po2(int n) { return 1 + (n|=(n|=(n|=(n|=(n|=(n-=1)>>(1<<0))>>(1<<1))>>(1<<2))>>(1<<3))>>(1<<4)); }

Esse é um comportamento indefinido em C ou C ++ e levará a erros. Modificar nvárias vezes sem um ponto de sequência é inválido. Você escreveu como se n-=1deveria acontecer primeiro, mas a única garantia aqui é que ncontém seu novo valor depois que ;os parênteses e não mudam isso.
— sam hocevar

Mais ao ponto, faz meus olhos sangrarem.
— Donal Fellows
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.