Bir sonraki 2 güce yuvarlama


190

2 numaraya en yakın sonraki gücü veren bir fonksiyon yazmak istiyorum. Örneğin, girdim 789 ise, çıktı 1024 olmalıdır. Bunu herhangi bir döngü kullanmadan, sadece bitsel operatörler kullanarak gerçekleştirmenin herhangi bir yolu var mı?



4
Açıklığa kavuşturmak gerekirse, 2'ye en yakın güce (yani 65 size 64 verecek, ama 100 size 128 verecek) ya da en yakınına (yani 65 size 128 verecek ve 100 verecek) ihtiyacınız var mı?
Kim Reece

1
Bu soruya uyan birden fazla soru. Örneğin: stackoverflow.com/questions/364985/…
Yann Droneaud

1
olası bir tamsayı
Nathan

7
@Nathan Bağlantınız bu sorudan 8 ay sonra .
Joseph Quinsey

Yanıtlar:


148

Bit Twiddling Hack'lerini kontrol edin . Temel 2 logaritmasını almanız ve ardından buna 1 eklemeniz gerekir. 32 bit değerine örnek:

Bir sonraki en yüksek güç 2'ye yuvarlayın

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

Diğer genişliklere olan uzantı açık olmalıdır.


11
Bu en verimli çözüm değildir çünkü birçok işlemci, log2'yi çok verimli bir şekilde hesaplamak için kullanılabilen önde gelen sıfırları saymak için özel talimatlara sahiptir. Bkz. En.wikipedia.org/wiki/Find_first_set
Simon

7
@Simon: bu taşınabilir çözüm. Tüm mimariler için ortak etkili bir algoritma yoktur
phuclv

5
Ya sayının kendisi ikinin gücü ise?
Litherum

6
Bu konuya hala iyi atıfta bulunuluyor, ancak bu cevap (ve diğerlerinin çoğu) çok eski. CPU'ların buna yardımcı olması için bir talimatı var (aslında o zaman zaten?). Gönderen: 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)); } Ve 32 bit için: uint32_t next_pow2(uint32_t x) { return x == 1 ? 1 : 1<<(32-__builtin_clz(x-1)); }Bu, GCC'yi (ve sanırım Clang'ı kullanırsanız), ancak zaman ayırmak akıllıca olur çevresindeki tüm seçenekleri kopyalamak yerine CLZ çağrısını bulun.
MappaM

2
@MappaM Bu cevap hala son derece alakalı ve bunu yapmanın en iyi taşınabilir yoludur. 64 bit sürümünüz x > UINT32_MAXdalsız değilse tanımsız bir davranışa sahiptir . Ayrıca, GCC ve Clang -mtune=genericvarsayılan olarak kullanılır (çoğu dağıtımda olduğu gibi), bu nedenle kodunuz lzcntx86_64'teki talimatlara genişlemez - böyle bir şey kullanmazsanız aslında çok daha yavaş bir şeye (libgcc rutin) genişler -march=native. Bu nedenle, önerilen değiştirme işleminiz taşınabilir olmayan, buggy ve (genellikle) daha yavaştır.
Craig Barnes

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

Bu, x elde etmek için 2 artıracağınız sayıyı bularak çalışır (sayının günlüğünü alın ve istenen tabanın günlüğüne bölün, daha fazla bilgi için wikipedia'ya bakın ). Sonra en yakın tam sayı gücünü elde etmek için tavana yuvarlayın.

Bu, başka bir yerde bağlantılı bitsel yöntemlerden daha genel bir amaç (yani daha yavaş!) Bir yöntemdir, ancak matematiği bilmek iyidir, ha?


3
C99'dan, araçlarınız tarafından destekleniyorsa log2'yi de kullanabilirsiniz . GCC ve VS şu şekilde görünmüyor :(
Matthew Read

2
Bir parantez eksik ... next = pow (2, tavan (log (x) / log (2)));
Matthieu Cormier

13
Bununla birlikte, şamandıra doğruluğu konusunda dikkatli olun. log(pow(2,29))/log(2)= 29.000000000000004, sonuç 2 29 döndürmek yerine 2 30'dur . Bence log2 fonksiyonları bu yüzden var mı?
endolit

48
Bunun maliyeti muhtemelen en az 200 döngüdür ve doğru bile değildir. Neden bu kadar çok oy var?
Axel Gneiting

4
@SuperflyJon Ama bitsel operatörlerden bahsediyor ve aksi belirtilmedikçe doğruluğun herhangi bir soru tarafından ima edildiğini varsayıyorum.
BlackJack

51

Bence bu da işe yarıyor:

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

Ve cevap power.


19
Yeterince adil soru döngüleri istedi. Ancak, diğer bazı işlevler kadar akıllı olduğu gibi, performansa duyarlı olmayan kodlar için hızlı ve kolay anlaşılan ve doğru olduğu doğrulanan cevap her zaman benim için kazanır.
Tim MB

2
Bu, 2'ye en yakın gücü
döndürmüyor

1
power <<= 1
Çarpmak

5
@Vallentin Bu bir derleyici tarafından otomatik olarak optimize edilmelidir.
MarkWeston

4
xÇok büyükse sonsuz döngüye dikkat edin (örn. 2'nin sonraki gücünü temsil etmek için yeterli bit yok).
alban

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
(Eğer keşfetmediyseniz) ilişkilendirirseniz iyi olurdu. Biraz dönen kesmek sayfasından geliyor.
florin

3
Bu 32 bitlik bir sayı için mi? 64-bit için uzantı?
Jonathan Leffler

Jonathan, üst yarı için yapman gerekiyor ve eğer bu sıfırsa, alt yarı için yapmalısın.
florin

5
@florin, v 64 bitlik bir türse, 16 için bir "c | = v >> 32" ekleyemez misiniz?
Evan Teran

3
Yalnızca belirli bir bit genişliği için çalışan kod, minimum genişlik türleri yerine sabit genişlikli türler kullanıyor olmalıdır. Bu işlev almalı ve geri dönmelidir a uint32_t.
Craig Barnes

36

GCC kullanıyorsanız, Lockless Inc. tarafından next_pow2 () işlevini en iyi duruma getirme konusuna göz atmak isteyebilirsiniz . Bu sayfada yerleşik işlev builtin_clz()(sıfır önde sayma) ve daha sonra doğrudan x86 (ia32) kullanımı montajcı talimat bsrbu bölümde açıklanan gibi (biraz tarama ters), başka bir yanıt 'ın GameDev sitesine bağlantı . Bu kod, önceki yanıtta açıklanan kodlardan daha hızlı olabilir .

Bu arada, montajcı talimatını ve 64 bit veri türünü kullanmayacaksanız, bunu kullanabilirsiniz

/**
 * 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
Bunun OR değerinden x'e eşit olan en küçük 2 değerini döndürdüğünü unutmayın. (X -1) değerini x olarak değiştirmek, x değerinden daha büyük 2'nin daha küçük gücünü döndürmek için işlevi değiştirir.
Guillaume

2
Sen kullanabilirsiniz _BitScanForwardVisual C ++
KindDragon

Ayrıca kullanabilirsiniz__builtin_ctz()
MarkP

@MarkP __builtin_ctz(), 2 sayının herhangi bir gücünü ikisinin bir sonraki gücüne yuvarlamak için yararlı olmayacaktır
Yann Droneaud

2
Lütfen yanıtınıza diğer derleyiciler için yerleşik bitsel işlevlerin Wikipedia listesine bir bağlantı ekleyin: en.wikipedia.org/wiki/Find_first_set#Tool_and_library_support                                Lütfen 64 bitlik bir sürüm de sağlayın. Aşağıdaki C ++ 11 işlevini öneriyorum:              constexpr uint64_t nextPowerOfTwo64 (uint64_t x) { return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x)); }
olibre

15

Bir tane daha, döngü kullanmama rağmen, matematik işlenenlerinden çok daha hızlı

iki "kat" seçeneğinin gücü:

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

iki "tavan" seçeneğinin gücü:

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

GÜNCELLEME

Yorumlarda belirtildiği gibi ceil, sonucunun yanlış olduğu yerde hata vardı .

İşte tam fonksiyonlar:

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
xgüç 2 ise sonuç doğru değildir. Giriş gücü 2 olup olmadığını test etmek için bir mikro gereklidir. #define ISPOW2(x) ((x) > 0 && !((x) & (x-1)))
pgplus1628

@zorksylar daha verimli olurduif (x == 0) return 1; /* Or 0 (Which is what I use) */ x--; /* Rest of program */
yyny

Güzel çözüm! ama power of two "ceil" optiondoğru değil. Örneğin, x = 2sonucu olmalıdır 2yerine4
MZD

10

İmzasız herhangi bir tür için, Bit Twiddling Hack'lerini temel alan:

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

Derleyici gerçekten yineleme sayısını bildiği için orada bir döngü yoktur.


4
Soru C hakkındadır.
martinkunev

@martinkunev Sadece UnsignedType'ı değiştirin ve manuel olarak işleyin. Bir C programcısının bu basit şablonu std::is_unsigned<UnsignedType>::valueiddiayı göz ardı ederek genişletebileceğinden eminim .
user877329

2
@ user877329 Tabii, birisinin bunu C'ye çevirmek
istemesi

@martinkunev JavaScript'te UnsignedType? Her neyse, bu çözüm herhangi bir UnsignedType için nasıl yapılacağını gösterir ve UnsignedType nesnesindeki bit sayısı gibi bir şey yerine sözde kod [sizeof (v) * CHAR_BIT] yerine C ++ ile yazılmış olur.
user877329

9

IEEE şamandıraları için böyle bir şey yapabilirsiniz.

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

Bir tamsayı çözümüne ihtiyacınız varsa ve satır içi montajı kullanabiliyorsanız, BSR size x86 üzerinde bir tamsayının log2'sini verecektir. Kaç tane doğru bitin ayarlandığını sayar, bu sayı tam olarak bu sayının log2 değerine eşittir. Diğer işlemciler CLZ gibi benzer talimatlara sahiptir (genellikle) ve derleyicinize bağlı olarak işi sizin için yapabilecek bir içsel olabilir.


Bu ilginç bir soru olsa da (sadece tamsayıları yuvarlamak istiyorum) soru ile ilgili değil, bunu deneyeceğim ..
Naveen

Yüzen wikipedia makalesini okuduktan sonra onunla geldi. Bunun yanı sıra, tamsayı hassasiyetinde kare kökleri hesaplamak için kullandım. Ayrıca güzel, ama daha da ilgisiz.
Jasper Bekkers

Bu, katı takma adlandırma kurallarını ihlal eder. Bazı derleyicilerde çalışmayabilir veya bir uyarı verebilir.
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
}

Tanımsız davranış alanına girmek istemiyorsanız, giriş değeri 1 ile 2 ^ 63 arasında olmalıdır. Makro, derleme zamanında sabit ayarlamak için de yararlıdır.


Bu muhtemelen en kötü çözümdür (64 bit sabitinde ULL soneki de yoktur). Bu, her durumda girdi başına 32 test üretecektir. Bir while döngüsü kullanmak daha iyidir, her zaman daha hızlı veya aynı hızda olacaktır.
xryl669

1
AMA ... eğer giriş sabit ise önişlemci tarafından değerlendirilebilir ve bu nedenle çalışma zamanında SIFIR işlemi!
Michael

4

Bütünlük için burada bataklık standart C'de kayan nokta uygulamasıdır.

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
Rastgele tarayıcılar, bu yorumu okursanız, bu kodu seçin. Neden başka hiç kimse onu reddetti ^^ tahmin
CoffeDeveloper

5
Rastgele tarayıcılar, özel kayan nokta donanımınız yoksa bu yavaş yavaş ölecektir. X86'da, bit döndürmeyi kullanarak bu kodun etrafında daireler çalıştırabilirsiniz. rep bsr ecx,eax; mov eax,0; cmovnz eax,2; shl eax,clyaklaşık 25 kat daha hızlıdır.
Johan

4

Tamsayı girişi için C / C ++ 'da etkili Microsoft'a (ör. Visual Studio 2017) özgü bir çözüm. En önemli 1 bitin konumunu kontrol etmeden önce, giriş değerini iki değerlik bir güçle tam olarak eşleştirerek azaltarak işleme koyar.

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

Bu, aşağıdakilere benzer bir Intel işlemci için 5 veya daha fazla satır içi talimat oluşturur:

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

Görünüşe göre Visual Studio C ++ derleyicisi bunu derleme zamanı değerleri için optimize etmek için kodlanmamış, ancak orada bir sürü talimat var gibi değil.

Düzenle:

1 giriş değerinin 1 (sıfırıncı güce 2) vermesini istiyorsanız, yukarıdaki kodda küçük bir değişiklik yapılsa da dalsız talimatlar doğrudan doğruya üretilir.

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

Birkaç talimat daha oluşturur. İşin püf noktası, Dizin'in bir test ve ardından bir cmove talimatı ile değiştirilebilmesidir.


Küçük bir hata: 1 için 1 dönmelidir, ama değil.
0kcats

Teşekkürler. Geliştirildiği uygulamada 1 girildiğinde ilk güce açıkça 2 ihtiyaç duyduk. 1 hayal edebileceğim çok fazla talimat üretmeden şartlı özel bir durum olarak ele alınabilir.
NoelC

Yanıt, 1 giriş değeri için 1 döndüren bir sürüm içerecek şekilde güncelleştirildi
NoelC

3

X86'da, hızlı yapmak için sse4 bit manipülasyon talimatlarını kullanabilirsiniz.

//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 ile eşleşen intrinsics kullanabilirsiniz.


Yararsız ama HARİKA!
Marco

3

İşte C'deki çözümüm. Umarım bu yardımcı olur!

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

0

Birçok işlemci mimarisi log base 2veya çok benzer bir işlemi destekler count leading zeros. Birçok derleyici bunun için kendine has özelliklere sahiptir. Bkz. Https://en.wikipedia.org/wiki/Find_first_set


en yüksek ayarlanmış biti (= bsr) bulmak veya baştaki sıfırları saymakla ilgili değildir. "2 çıkar, sonra bsr yap ve 1 sola kaydır" ile cevabını 2. en yakın güce yuvarlamak istiyor .
Flo

0

Eğer iyi bir derleyici var varsayalım & bu noktada üstümde şu elden önce biraz twiddling yapabilir, ama yine de bu çalışıyor !!!

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

Aşağıdaki test kodu:

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

Çıktılar:

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

En yakın düşük 2 gücü almaya çalışıyorum ve bu işlevi yaptım. Size yardımcı olabilir. 2'ye en yakın üst gücü elde etmek için en yakın düşük sayı 2'yi çarpın

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

Paul Dixon'un Excel'e cevabı uyarlandı, bu mükemmel çalışıyor.

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

0

@YannDroneaud yanıtının bir çeşidi x==1, yalnızca x86 plaka formları , derleyiciler, gcc veya clang için geçerlidir:

__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

Giriş sabit bir ifade ise, bu sabit bir ifade olması için kullanıyorum.

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

Örneğin, şöyle bir ifade:

uptopow2(sizeof (struct foo))

bir sabite indirgeyecek.


0

Amacınıza yardımcı olmak için aşağıdaki açıklamaları bulabilirsiniz:


0

Bir kayan noktaya dönüştürün ve sonra normalleştirilmiş IEEE gösterimini gösteren .hex () yöntemini kullanın.

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

Sonra üssü çıkarın ve 1 ekleyin.

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

Ve bu güce 2 yükseltin.

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


Bu cevabın
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

OpenGL ile ilgili şeyler için ihtiyacınız varsa:

/* 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' bir döngüdür.
florin

1
florin: öyle. ve burada bir döngü olarak kullanılıyor, değil mi?
Tamas Czinege

9
DrJokepu - Bence florin burada OP'nin
döngüsüz bir

-1

Tek satırlık bir şablon istiyorsanız. İşte burada

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

veya

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

Bu, C veya C ++ 'da tanımlanmamış bir davranıştır ve hatalara yol açar. Değiştirme nbir dizi noktası olmadan defalarca geçersiz. n-=1İlk önce olması gerektiği gibi yazdınız, ancak buradaki tek garanti, nsonradan yeni değerini içeren ;ve parantezlerin bunu değiştirmediğidir.
sam hocevar

Daha da önemlisi, gözlerimi kanıyor.
Donal Fellows
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.