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?

Naveen
fonte
4
Veja aqui algumas das possíveis soluções: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float
Stefan
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.

florim
fonte
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 é?

Paul Dixon
fonte
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;

}
Eclipse
fonte
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.

Jose Dagoberto
fonte
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));
}
Yann Droneaud
fonte
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;
}
vlk
fonte
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.

Robson
fonte
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ê.

Jasper Bekkers
fonte
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
6

Apesar da pergunta está marcado como caqui meus cinco centavos. Para nossa sorte, o C ++ 20 incluiria std::ceil2e std::floor2(veja aqui ). São consexprfunções de modelo, a implementação atual do GCC usa deslocamento de bits e funciona com qualquer tipo integral não assinado.

kreuzerkrieg
fonte
2
Eles o renomearam recentemente para bit_ceil open-std.org/JTC1/SC22/WG21/docs/papers/2020/p1956r1.pdf
Wolfgang Brehm
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.

Philip J. Fry
fonte
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);
}
doynax
fonte
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.

NoelC
fonte
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.

Johan
fonte
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;
}
Kevin Yang
fonte
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

Simon
fonte
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
nimig18
fonte
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;
}
Cody Piersall
fonte
0

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

 =POWER(2,CEILING.MATH(LOG(A1)/LOG(2)))
Tim Tharratt
fonte
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);
}
Oliv
fonte
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.

Kaz
fonte
0

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

Aashay Sathe
fonte
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

David Wallace
fonte
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
Yossarian42
fonte
-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;
    }
}
Paulo Lopes
fonte
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)); }
Vo Hoang Anh
fonte
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