2의 다음 거듭 제곱으로 반올림


189

가장 가까운 다음 2의 거듭 제곱을 반환하는 함수를 작성하고 싶습니다. 예를 들어 내 입력이 789 인 경우 출력은 1024 여야합니다. 루프를 사용하지 않고 비트 연산자 만 사용하여이를 달성 할 수있는 방법이 있습니까?


4
가능한 해결책은 여기를 참조하십시오 : http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float
Stefan

4
설명을 위해 가장 가까운 2의 제곱이 필요합니까 (즉, 65는 64를 주지만 100은 128을 줄 것입니다) 또는 가장 가까운 위의 것 (즉, 65는 128을 줄 것이므로 100도)을 필요로합니까?
Kim Reece 2012 년

1
그들은 이것과 일치하는 여러 질문입니다. 예를 들면 다음과 같습니다. stackoverflow.com/questions/364985/…
Yann Droneaud


7
귀하의 링크 @Nathan 8개월입니다 나중에 이 질문보다.
Joseph Quinsey

답변:


148

Bit Twiddling Hacks를 확인하십시오 . 밑이 2 인 로그를 구한 다음 1을 더해야합니다. 32 비트 값의 예 :

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++;

다른 폭으로의 확장은 분명해야합니다.


11
많은 프로세서가 log2를 매우 효율적으로 계산하는 데 사용할 수있는 선행 0을 계산하는 특수 명령을 가지고 있기 때문에 이것은 가장 효율적인 솔루션이 아닙니다. 참조 en.wikipedia.org/wiki/Find_first_set
사이먼

7
@Simon : 휴대용 솔루션입니다. 모든 아키텍처에 대해 효율적인 효율적인 알고리즘이 없습니다
phuclv

5
숫자 자체가 2의 거듭 제곱이면 어떻게 되나요?
Litherum

5
이 스레드는 여전히 잘 참조되지만이 답변 (및 대부분의 다른 답변)은 매우 구식입니다. CPU는 이것을 실제로 도와 줄 지시를 가지고 있습니다 (실제로 이미 그 당시?). from : 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)); } 그리고 32 비트 : uint32_t next_pow2(uint32_t x) { return x == 1 ? 1 : 1<<(32-__builtin_clz(x-1)); }GCC (그리고 Clang이라고 생각합니까?)를 사용한다면 시간이 걸리는 것이 현명합니다. 주변의 모든 옵션을 복사하여 붙여 넣는 대신 CLZ에 대한 호출을 찾으십시오.
MappaM

2
@MappaM이 답변은 여전히 ​​관련성이 높고 이식성이 가장 좋은 방법입니다. x > UINT32_MAX분기가없는 경우 64 비트 버전에 정의되지 않은 동작 이 있습니다. 또한 GCC와 Clang -mtune=generic은 기본적으로 (대부분의 배포판과 마찬가지로) 코드를 사용하므로 lzcntx86_64 의 명령으로 코드가 확장되지 않습니다 -march=native. 따라서 제안 된 대체품은 이식성이없고, 버그가 있으며 (보통) 느립니다.
Craig Barnes

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

이것은 x를 얻기 위해 2를 올린 숫자를 찾아서 작동합니다 (숫자의 로그를 가져 와서 원하는 기본의 로그로 나눕니다 . 자세한 내용은 wikipedia 참조 ). 그런 다음 ceil로 반올림하여 가장 가까운 정수 전력을 얻습니다.

이것은 다른 곳에서 연결된 비트 방식보다 일반적인 목적 (즉, 느리게!)이지만 수학을 아는 것이 좋습니다.


3
C99에서 도구가 지원하는 경우 log2 만 사용할 수도 있습니다. GCC와 VS는 다음과 같이 보이지 않습니다 :(
Matthew Read

2
괄호가 없습니다 ... next = pow (2, ceil (log (x) / log (2)));
Matthieu Cormier

13
그러나 플로트 정확도에주의하십시오. log(pow(2,29))/log(2)= 29.000000000000004, 결과는 2 29 를 반환하는 대신 2 30 입니다. 이것이 log2 함수가 존재하는 이유라고 생각합니다.
endolith

48
이것의 비용은 아마도 적어도 200주기이며 정확하지 않습니다. 왜 이렇게 많은 투표가 있습니까?
Axel Gneiting

4
@SuperflyJon 그러나 비트 연산자를 언급하고 달리 언급하지 않는 한 모든 질문에 정확성이 암시되어 있다고 가정합니다.
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
당신이 그것을 평가하지 않으면 좋을 것입니다 (발견하지 않는 한). 비트 트위들 링 해킹 페이지에서 가져옵니다.
florin 2012 년

3
32 비트 숫자입니까? 64 비트 확장?
Jonathan Leffler

조나단, 당신은 상반기를 위해 그것을해야하고, 그것이 0이라면, 당신은 하반부를 위해 그것을해야합니다.
florin 2012 년

5
@florin, 만약 v가 64 비트 타입이라면, 16을 위해 "c | = v >> 32"를 추가 할 수 없습니까?
에반 테란

3
특정 비트 너비에 대해서만 작동하는 코드는 최소 너비 유형 대신 고정 너비 유형을 사용해야합니다. 이 함수는를 가져와야합니다 uint32_t.
Craig Barnes

50

나는 이것이 작동한다고 생각한다.

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

대답은 power입니다.


19
공정하게 질문은 루프를 요구하지 않았습니다. 그러나 다른 기능 중 일부와 마찬가지로 영리합니다. 성능에 민감하지 않은 코드의 경우 빠르고 쉽게 이해되고 정확하다는 대답은 항상 나에게 도움이됩니다.
Tim MB

2
이것은 2의 가장 가까운 거듭 제곱을 반환하지 않지만, 그 거듭 제곱은 즉시 X보다 큽니다. 여전히 매우 좋습니다
CoffeDeveloper

1
대신 곱의 일부 비트 "마법"대신 사용할 수 있습니다power <<= 1
vallentin

5
@Vallentin 컴파일러가 자동으로 최적화해야합니다.
MarkWeston

4
x너무 큰 경우 무한 루프에주의하십시오 (즉, 2의 다음 거듭 제곱을 나타내기에 충분한 비트가 아님).
alban

36

GCC를 사용하는 경우 Lockless Inc. 의 next_pow2 () 함수 최적화를 참조하십시오.이 페이지는 내장 함수 builtin_clz()(제로 선행 0)를 사용하고 나중에 직접 x86 (ia32) 을 사용하는 방법을 설명합니다. gamedev 사이트에 대한 다른 답변링크에bsr 설명 된 것처럼 어셈블러 명령어 (비트 스캔 역) . 이 코드는 이전 답변 에서 설명한 것보다 빠를 수 있습니다 .

그건 그렇고, 어셈블러 명령어와 64 비트 데이터 타입을 사용하지 않는다면 이것을 사용할 수 있습니다

/**
 * 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
이는 x보다 OR보다 큰 2의 가장 작은 거듭 제곱을 반환합니다. (x -1)을 x로 변경하면 x보다 큰 2의 더 작은 제곱을 반환하도록 함수가 변경됩니다.
기 illa

2
_BitScanForwardVisual C ++에서 사용할 수 있습니다
KindDragon

다음을 사용할 수도 있습니다__builtin_ctz()
MarkP

@MarkP __builtin_ctz()는 2의 비 거듭 제곱을 다음 2의 거듭 제곱으로 반올림하는 데 유용하지 않습니다.
Yann Droneaud

2
다른 컴파일러를위한 내장 비트 단위 함수의 위키피디아 목록에 대한 링크를 답변에 추가하십시오. en.wikipedia.org/wiki/Find_first_set#Tool_and_library_support                                64 비트 버전도 제공하십시오. 나는 다음과 같은 C ++ 11 함수를 제안한다 :              constexpr uint64_t nextPowerOfTwo64 (uint64_t x) { return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x)); }
olibre

15

하나 더, 사이클을 사용하지만 수학 피연산자보다 훨씬 빠릅니다.

두 개의 "바닥"옵션의 힘 :

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

두 개의 "천장"옵션의 힘 :

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

최신 정보

의견에서 언급했듯이 ceil결과가 잘못 된 곳에 실수가있었습니다 .

전체 기능은 다음과 같습니다.

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
만약 결과가 올바르지 않은 x입력이 필요하다 (2)의 전원이있는 경우에 테스트 2. 마이크로 전력이다. #define ISPOW2(x) ((x) > 0 && !((x) & (x-1)))
pgplus1628

@zorksylar는 더 효율적일 것입니다if (x == 0) return 1; /* Or 0 (Which is what I use) */ x--; /* Rest of program */
yyny

좋은 해결책! 그러나 power of two "ceil" option올바르지 않습니다. 예를 들어 x = 2결과가 다음 2과 같이 4
바뀌어야

10

비트 트위들 링 해킹을 기반으로하는 서명되지 않은 유형의 경우 :

#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;
}

컴파일러가 컴파일 타임에 반복 횟수를 알고 있기 때문에 실제로 루프가 없습니다.


4
질문은 C에 관한 것입니다.
martinkunev

@martinkunev UnsignedType을 바꾸고 수동으로 처리하십시오. C 프로그래머가 std::is_unsigned<UnsignedType>::value어설 션을 무시 하고이 간단한 템플릿을 확장 할 수 있다고 확신합니다 .
user877329 2016 년

2
@ user877329 물론 누군가가
이것을

JavaScript에서 @martinkunev UnsignedType? 어쨌든,이 솔루션은 UnsignedType에 대해 수행하는 방법을 보여 주며 의사 코드 [UnsignedType의 객체의 비트 수와 같은 대신 pseudocode [sizeof (v) * CHAR_BIT) 대신 C ++로 작성됩니다.
user877329 2016 년

9

IEEE float의 경우 다음과 같은 작업을 수행 할 수 있습니다.

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)); 
}

정수 솔루션이 필요하고 인라인 어셈블리를 사용할 수있는 경우 BSR은 x86에서 정수의 log2를 제공합니다. 얼마나 많은 오른쪽 비트가 설정되어 있는지 계산합니다. 이는 해당 숫자의 log2와 정확히 같습니다. 다른 프로세서에는 CLZ와 같은 유사한 지침이 있으며 (종종) 컴파일러에 따라 작업을 수행하는 데 본질적인 기능이있을 수 있습니다.


이것은 질문과 관련이 없지만 흥미로운 것입니다 (정수만 반올림하고 싶습니다). 이것을 시도해보십시오.
Naveen

수레에 관한 wikipedia 기사를 읽은 후에 생각해 냈습니다. 그 외에도 정수 정밀도로 제곱근을 계산하는 데 사용했습니다. 또한 좋지만 더 관련이 없습니다.
Jasper Bekkers

이것은 엄격한 앨리어싱 규칙을 위반합니다. 일부 컴파일러에서는 작동하지 않거나 경고를 발행 할 수 있습니다.
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
}

정의되지 않은 동작 영역으로 들어 가지 않으려면 입력 값이 1과 2 ^ 63 사이 여야합니다. 이 매크로는 컴파일 타임에 상수를 설정하는데도 유용합니다.


이것은 아마도 최악의 솔루션 일 것입니다 (64 비트 상수에서 ULL 접미사가 누락되었습니다). 모든 경우에 입력 당 32 개의 테스트가 생성됩니다. while 루프를 사용하는 것이 좋을수록 항상 더 빠르거나 같은 속도로 작동합니다.
xryl669

1
그러나 ...이 입력이 일정하면 런타임에 ZERO 작동 인 경우 전 처리기에서 평가할 수 있습니다!
Michael

4

완전성을 위해 여기에는 bog 표준 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
임의의 브라우저는이 주석을 읽으면이 코드를 선택하십시오. 이것은 명백히 최선의 답변, 특별한 지침, 비트 트위들 링, 효율적이고 휴대 가능하고 표준적인 코드입니다. 왜 아무도 그것을
공표

5
임의의 브라우저, 특수 부동 소수점 하드웨어가 없으면 속도가 느려집니다. x86에서는 비트 twiddling을 사용하여이 코드 주위에 원을 실행할 수 있습니다. rep bsr ecx,eax; mov eax,0; cmovnz eax,2; shl eax,cl약 25 배 빠릅니다.
Johan

4

정수 입력을위한 C / C ++의 효율적인 Microsoft (예 : Visual Studio 2017) 특정 솔루션입니다. 가장 중요한 1 비트의 위치를 ​​확인하기 전에 감소시켜 두 값의 거듭 제곱과 정확히 일치하는 입력의 경우를 처리합니다.

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

그러면 다음과 유사한 인텔 프로세서에 대해 5 개 정도의 인라인 명령어가 생성됩니다.

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

분명히 Visual Studio C ++ 컴파일러는 컴파일 타임 값을 위해 이것을 최적화하도록 코딩되지 않았지만 거기에 많은 명령이있는 것은 아닙니다.

편집하다:

1의 입력 값이 1 (2에서 0의 제곱 거듭 제곱)을 생성하도록하려면 위 코드를 약간만 수정해도 분기가없는 명령을 통해 직접 생성됩니다.

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

몇 가지 명령 만 더 생성합니다. 요령은 인덱스를 테스트와 cmove 명령으로 대체 할 수 있다는 것입니다.


작은 실수 : 1을 1로 반환해야하지만 그렇지 않습니다.
0kcats

감사. 그것이 개발 된 어플리케이션에서 우리는 1이 입력 될 때 첫 번째 힘에 2를 명시 적으로 필요로했다. 1은 내가 상상하는 너무 많은 지시를 생성하지 않고 조건부와 함께 특별한 경우로 취할 수 있습니다.
NoelC

입력 값이 1 인 경우 1을 반환하는 버전을 포함하도록 답변을 업데이트했습니다.
NoelC

3

x86에서는 sse4 비트 조작 명령을 사용하여 빠르게 만들 수 있습니다.

//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

c에서는 일치하는 내장 함수를 사용할 수 있습니다.


쓸모 없지만 굉장합니다!
Marco

3

여기 C의 솔루션이 있습니다. 도움이 되길 바랍니다.

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

0

많은 프로세서 아키텍처가 log base 2매우 유사한 작업을 지원 합니다 – – count leading zeros. 많은 컴파일러가 내장 함수를 가지고 있습니다. 참조 https://en.wikipedia.org/wiki/Find_first_set를


가장 높은 세트 비트 (= bsr)를 찾거나 선행 0을 계산하는 것이 아닙니다. 그는 싶어 모아 "BSR을 한 후, 1 빼기 1은 왼쪽으로 이동"그와 함께 않습니다 2. 대답의 가장 가까운 전원.
Flo

0

좋은 컴파일러가 있다고 가정하면이 시점에서 나보다 앞서있는 비트 손질을 할 수 있지만 어쨌든 이것이 작동합니다!

    // 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)))

아래 테스트 코드 :

#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);
}

출력 :

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

가장 가까운 2의 더 낮은 전력을 얻으려고 노력 하고이 기능을 만들었습니다. 가장 가까운 더 낮은 수에 2를 곱하여 가장 가까운 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

Excel에 대한 Paul Dixon의 답변에 따라 완벽하게 작동합니다.

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

0

@YannDroneaud 응답의 변형은 x==1x86 플레이트, 컴파일러, gcc 또는 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

입력이 상수 표현식 인 경우 상수 표현식이되도록 사용하고 있습니다.

#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 */

예를 들어 다음과 같은 표현식은

uptopow2(sizeof (struct foo))

일정하게 줄어 듭니다.



0

float로 변환 한 다음 표준화 된 IEEE 표현을 보여주는 .hex ()를 사용하십시오.

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

그런 다음 지수를 추출하고 1을 더하십시오.

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

그리고이 힘을 2로 올립니다.

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


이 답변은 파이썬에 참고
데이비드 월러스

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

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'는 루프입니다.
florin 2012 년

1
플로린 : 그렇습니다. 여기 루프로 사용되지 않습니까?
Tamas Czinege 2012 년

9
DrJokepu-플로린이 여기서 OP가 루프리스 솔루션을 요청했다고 말한 것 같습니다
Eli Bendersky

-1

한 줄 템플릿을 원한다면. 여기있어

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

또는

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

이것은 C 또는 C ++에서 정의되지 않은 동작이며 오류가 발생합니다. n시퀀스 포인트없이 여러 번 수정 하는 것은 유효하지 않습니다. 당신은 그것을 n-=1먼저 해야하는 것처럼 썼지 만 여기서 유일한 보증 은 괄호가 그것을 바꾸지 않은 n후에 새로운 가치 를 포함 ;한다는 것입니다.
sam hocevar

요컨대, 내 눈을 피가 난다.
Donal Fellows
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.