Làm tròn đến sức mạnh tiếp theo của 2


187

Tôi muốn viết một hàm trả về lũy thừa tiếp theo là 2 số. Ví dụ: nếu đầu vào của tôi là 789, thì đầu ra phải là 1024. Có cách nào để đạt được điều này mà không cần sử dụng bất kỳ vòng lặp nào mà chỉ sử dụng một số toán tử bitwise không?


4
Xem tại đây để biết các giải pháp khả thi: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float
Stefan

4
Bằng cách làm rõ, bạn có cần sức mạnh gần nhất bằng 2 (tức là 65 sẽ cung cấp cho bạn 64, nhưng 100 sẽ cung cấp cho bạn 128) hoặc gần nhất ở trên (ví dụ: 65 sẽ cung cấp cho bạn 128, và 100 cũng vậy)?
Kim Reece

1
Có nhiều câu hỏi phù hợp với câu hỏi này. Ví dụ: stackoverflow.com/questions/364985/ cường
Yann Droneaud


7
@Nathan Liên kết của bạn muộn hơn 8 tháng so với câu hỏi này.
Joseph Quinsey

Câu trả lời:


146

Kiểm tra các hack Twiddling Bit . Bạn cần lấy logarit cơ sở 2, sau đó thêm 1 vào đó. Ví dụ cho giá trị 32 bit:

Làm tròn đến sức mạnh cao nhất tiếp theo là 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++;

Việc mở rộng cho các chiều rộng khác nên rõ ràng.


11
Đây không phải là giải pháp hiệu quả nhất vì nhiều bộ xử lý có hướng dẫn đặc biệt để đếm các số 0 hàng đầu có thể được sử dụng để tính toán log2 rất hiệu quả. Xem en.wikipedia.org/wiki/Find_first_set
Simon

7
@Simon: đó là giải pháp di động. Không có thuật toán hiệu quả chung cho tất cả các kiến ​​trúc
phuclv

5
Điều gì nếu số lượng chính nó là một sức mạnh của hai?
Litherum

5
Chủ đề này vẫn được tham khảo tốt nhưng câu trả lời này (và hầu hết những người khác) đã rất lỗi thời. CPU có một hướng dẫn để giúp điều này (thực sự đã có tại thời điểm đó?). Từ: 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)); } Và trong 32 bit: uint32_t next_pow2(uint32_t x) { return x == 1 ? 1 : 1<<(32-__builtin_clz(x-1)); }Đó là nếu bạn sử dụng GCC (và Clang tôi nghĩ sao?), Nhưng sẽ là khôn ngoan khi dành thời gian để tìm cuộc gọi đến CLZ thay vì dán tất cả các tùy chọn xung quanh.
MappaM

2
@MappaM Câu trả lời này vẫn rất phù hợp và là cách di động tốt nhất để làm điều đó. Phiên bản 64 bit của bạn có hành vi không xác định nếu x > UINT32_MAXvà không phân nhánh. Ngoài ra, GCC và Clang sử dụng -mtune=generictheo mặc định (như hầu hết các bản phân phối), vì vậy mã của bạn sẽ KHÔNG mở rộng thành lzcnthướng dẫn trên x86_64 - nó thực sự sẽ mở rộng sang thứ gì đó chậm hơn (một thói quen libgcc) trừ khi bạn sử dụng một cái gì đó như -march=native. Vì vậy, đề xuất thay thế của bạn là không di động, lỗi và (thường) chậm hơn.
Craig Barnes

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

Điều này hoạt động bằng cách tìm số bạn đã tăng 2 bằng cách lấy x (lấy nhật ký của số và chia cho nhật ký của cơ sở mong muốn, xem wikipedia để biết thêm ). Sau đó làm tròn nó lên với trần để có được toàn bộ số điện gần nhất.

Đây là một phương pháp có mục đích chung hơn (tức là chậm hơn!) So với các phương thức bitwise được liên kết ở nơi khác, nhưng tốt để biết các phép toán, eh?


3
Từ C99, bạn cũng có thể chỉ cần sử dụng log2 nếu được các công cụ của bạn hỗ trợ. GCC và VS dường như không :(
Matthew Đọc

2
Bạn đang thiếu một dấu ngoặc ... next = pow (2, ceil (log (x) / log (2)));
Matthieu Cormier

13
Hãy cẩn thận về độ chính xác của float, mặc dù. log(pow(2,29))/log(2)= 29.000000000000004, vì vậy kết quả là 2 30 thay vì trả về 2 29. Tôi nghĩ đây là lý do tại sao các hàm log2 tồn tại?
endolith

45
Chi phí của việc này có lẽ ít nhất là 200 chu kỳ và thậm chí còn không đúng. Tại sao điều này có rất nhiều upvote?
Axel Gneiting 18/08/2015

4
@SuperflyJon Nhưng nó đề cập đến các toán tử bitwise và tôi cho rằng tính chính xác được ngụ ý bởi bất kỳ câu hỏi nào trừ khi có ghi chú khác.
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
Sẽ tốt hơn nếu bạn đã gán nó (trừ khi bạn phát hiện ra nó). Nó đến từ các trang hack hack twiddling.
florin

3
Đó có phải là số 32 bit không? Gia hạn cho 64-bit?
Jonathan Leffler

Jonathan, bạn cần phải làm điều đó cho nửa trên, và nếu đó là số không, bạn làm điều đó cho nửa dưới.
florin

5
@florin, nếu v là loại 64 bit, bạn không thể thêm "c | = v >> 32" sau loại 16?
Evan Teran

3
Mã chỉ hoạt động cho một chiều rộng bit cụ thể nên sử dụng các loại chiều rộng cố định thay vì các loại chiều rộng tối thiểu. Hàm này sẽ lấy và trả về a uint32_t.
Craig Barnes

50

Tôi nghĩ rằng điều này cũng hoạt động:

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

Và câu trả lời là power.


18
Đủ công bằng các câu hỏi yêu cầu không có vòng lặp. Nhưng thông minh như một số chức năng khác, đối với mã không nhạy với hiệu năng, câu trả lời nhanh chóng và dễ hiểu và được xác minh là chính xác luôn luôn thắng đối với tôi.
Tim MB

2
Điều này không trả lại sức mạnh gần nhất bằng 2, nhưng sức mạnh của nó ngay lập tức lớn hơn X. Vẫn rất tốt
CoffeDeveloper

1
Thay vì nhân lên, một số "ma thuật" bitwise có thể được sử dụng thay thếpower <<= 1
vallentin

5
@Vallentin Điều đó sẽ được tự động tối ưu hóa bởi trình biên dịch.
MarkWeston

4
Coi chừng vòng lặp vô hạn nếu xquá lớn (tức là không đủ bit để thể hiện sức mạnh tiếp theo của 2).
alban

36

Nếu bạn đang sử dụng GCC, bạn có thể muốn xem Tối ưu hóa chức năng next_pow2 () của Lockless Inc .. Trang này mô tả cách sử dụng chức năng tích hợp builtin_clz()(đếm số 0) và sau đó sử dụng trực tiếp x86 (ia32) hướng dẫn trình biên dịch chương trình bsr(quét ngược bit), giống như được mô tả trong liên kết của câu trả lời khác với trang web gamedev . Mã này có thể nhanh hơn mã được mô tả trong câu trả lời trước .

Nhân tiện, nếu bạn không sử dụng hướng dẫn trình biên dịch và kiểu dữ liệu 64 bit, bạn có thể sử dụng

/**
 * 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
Lưu ý rằng điều này trả về công suất nhỏ nhất bằng 2 lớn hơn OR bằng x. Thay đổi (x -1) thành x thay đổi hàm để trả về công suất nhỏ hơn 2 lớn hơn x.
Guillaume

2
Bạn có thể sử dụng _BitScanForwardtrên Visual C ++
KindDragon

Bạn cũng có thể sử dụng__builtin_ctz()
MarkP

@MarkP __builtin_ctz()sẽ không hữu ích để làm tròn bất kỳ số không có 2 số nào cho tới số tiếp theo của hai số
Yann Droneaud

2
Vui lòng thêm vào câu trả lời của bạn một liên kết đến danh sách các hàm dựng sẵn của Wikipedia cho các trình biên dịch khác: en.wikipedia.org/wiki/Find_first_set#Tool_and_l Library_support                                Vui lòng cung cấp phiên bản 64 bit. Tôi đề xuất chức năng C ++ 11 sau:              constexpr uint64_t nextPowerOfTwo64 (uint64_t x) { return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x)); }
olibre

15

Một lần nữa, mặc dù tôi sử dụng chu trình, nhưng thi nhanh hơn nhiều so với toán hạng toán học

sức mạnh của hai tùy chọn "sàn":

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

sức mạnh của hai tùy chọn "trần":

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

CẬP NHẬT

Như đã đề cập trong các bình luận, đã có sai lầm trong ceilđó kết quả của nó là sai.

Dưới đây là các chức năng đầy đủ:

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
kết quả không chính xác nếu xlà công suất của 2. Một micro để kiểm tra nếu đầu vào là công suất 2 là cần thiết. #define ISPOW2(x) ((x) > 0 && !((x) & (x-1)))
pgplus1628

@zorkylar hiệu quả hơn sẽ làif (x == 0) return 1; /* Or 0 (Which is what I use) */ x--; /* Rest of program */
yyny

Giải pháp tốt! nhưng power of two "ceil" optionkhông đúng Ví dụ: khi x = 2kết quả nên 2thay vì4
MZD

10

Đối với bất kỳ loại không dấu nào, hãy xây dựng trên 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;
}

Thực sự không có một vòng lặp ở đó vì trình biên dịch biết tại thời điểm biên dịch số lần lặp.


4
Lưu ý rằng câu hỏi là về C.
martinkunev

@martinkunev Chỉ cần thay thế UnsignType và xử lý thủ công. Tôi khá chắc chắn rằng một lập trình viên C có thể mở rộng mẫu đơn giản này mà bỏ qua std::is_unsigned<UnsignedType>::valuekhẳng định.
dùng877329

2
@ user877329 Chắc chắn, thật tuyệt khi có câu trả lời bằng Javascript, chỉ trong trường hợp ai đó muốn dịch nó sang C.
martinkunev

@martinkunev UnsignType trong JavaScript? Dù sao, giải pháp này cho thấy cách thực hiện đối với bất kỳ UnsignType nào và nó được viết bằng C ++, thay vì mã giả [sizeof (v) * CHAR_BIT thay vì một số thứ như số bit trong một đối tượng của UnsignType].
dùng877329

9

Đối với phao nổi của IEEE, bạn có thể làm một cái gì đó như thế này.

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

Nếu bạn cần một giải pháp số nguyên và bạn có thể sử dụng lắp ráp nội tuyến, BSR sẽ cung cấp cho bạn log2 của một số nguyên trên x86. Nó đếm có bao nhiêu bit phải được đặt, chính xác bằng log2 của số đó. Các bộ xử lý khác có các hướng dẫn tương tự (thường), chẳng hạn như CLZ và tùy thuộc vào trình biên dịch của bạn, có thể có sẵn một bản chất để thực hiện công việc cho bạn.


Đây là một sự kiện thú vị không liên quan đến câu hỏi (tôi chỉ muốn làm tròn số nguyên), sẽ thử bài này ..
Naveen

Đến với nó sau khi đọc bài viết trên wikipedia về phao. Ngoài ra, tôi đã sử dụng nó để tính căn bậc hai với độ chính xác nguyên. Cũng tốt đẹp, nhưng thậm chí nhiều hơn không liên quan.
Jasper Bekkers

Điều này phá vỡ các quy tắc răng cưa nghiêm ngặt. Trên một số trình biên dịch, nó có thể không hoạt động hoặc đưa ra cảnh báo.
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
}

Nếu bạn không muốn mạo hiểm vào vương quốc của hành vi không xác định, giá trị đầu vào phải nằm trong khoảng từ 1 đến 2 ^ 63. Macro cũng hữu ích để đặt hằng số tại thời gian biên dịch.


Đây có lẽ là giải pháp tồi tệ nhất (nó cũng thiếu hậu tố ULL trên hằng số 64 bit). Điều này sẽ tạo ra 32 thử nghiệm cho mỗi đầu vào trong mọi trường hợp. Tốt hơn là sử dụng vòng lặp while, nó sẽ luôn nhanh hơn hoặc ở cùng tốc độ.
xryl669

1
NHƯNG ... điều này có thể được đánh giá bởi bộ xử lý trước nếu đầu vào là một hằng số, và do đó ZERO hoạt động trong thời gian chạy!
Michael

4

Để hoàn thiện ở đây là một triển khai dấu phẩy động trong tiêu chuẩn 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
Các trình duyệt ngẫu nhiên, nếu bạn đọc nhận xét này, hãy chọn mã này. Đây rõ ràng là câu trả lời tốt nhất, không có hướng dẫn đặc biệt, không vặn vẹo một chút, chỉ là mã hiệu quả, di động và tiêu chuẩn. Đoán xem tại sao không ai khác nâng cấp nó ^^
CoffeDeveloper

5
Các trình duyệt ngẫu nhiên, điều này sẽ bị chậm nếu bạn không có phần cứng dấu phẩy động chuyên dụng. Trên x86, bạn có thể chạy các vòng tròn xung quanh mã này bằng cách sử dụng bit twiddling. rep bsr ecx,eax; mov eax,0; cmovnz eax,2; shl eax,clnhanh hơn khoảng 25 lần.
Johan

4

Một giải pháp cụ thể hiệu quả của Microsoft (ví dụ: Visual Studio 2017) trong C / C ++ cho đầu vào số nguyên. Xử lý trường hợp đầu vào khớp chính xác với công suất hai giá trị bằng cách giảm trước khi kiểm tra vị trí của 1 bit quan trọng nhất.

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

Điều này tạo ra 5 hoặc nhiều hướng dẫn nội tuyến cho bộ xử lý Intel tương tự như sau:

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

Rõ ràng trình biên dịch Visual Studio C ++ không được mã hóa để tối ưu hóa điều này cho các giá trị thời gian biên dịch, nhưng nó không giống như có rất nhiều hướng dẫn ở đó.

Biên tập:

Nếu bạn muốn giá trị đầu vào là 1 để mang lại 1 (2 cho công suất zeroth), một sửa đổi nhỏ cho mã trên vẫn tạo ra thông qua các hướng dẫn không có chi nhánh.

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

Tạo ra chỉ một vài hướng dẫn. Thủ thuật là Index có thể được thay thế bằng một bài kiểm tra theo hướng dẫn cmove.


Một lỗi nhỏ: Nó sẽ trả về 1 cho 1, mặc dù không.
0kcats

Cảm ơn. Trong ứng dụng được phát triển, chúng tôi rõ ràng cần 2 đến nguồn đầu tiên khi 1 là đầu vào. 1 có thể được coi là một trường hợp đặc biệt với một điều kiện mà không tạo ra quá nhiều hướng dẫn tôi tưởng tượng.
NoelC

Đã cập nhật câu trả lời để bao gồm phiên bản trả về 1 cho giá trị đầu vào là 1.
NoelC

3

Trong x86, bạn có thể sử dụng các hướng dẫn thao tác bit sse4 để làm cho nó nhanh.

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

Trong c bạn có thể sử dụng nội tại phù hợp.


Vô dụng nhưng TUYỆT VỜI!
Marco

3

Đây là giải pháp của tôi trong C. Hy vọng điều này sẽ giúp!

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

0

Nhiều kiến ​​trúc bộ xử lý hỗ trợ log base 2hoặc hoạt động rất giống nhau - count leading zeros. Nhiều trình biên dịch có nội tại cho nó. Xem https://en.wikipedia.org/wiki/Find_first_set


không phải là tìm bit được đặt cao nhất (= bsr) hoặc đếm các số 0 đứng đầu. anh ta muốn làm tròn đến sức mạnh gần nhất của 2. câu trả lời với "trừ 1, sau đó làm bsr và thay đổi 1 trái" thực hiện điều đó.
Flo

0

Giả sử bạn có một trình biên dịch tốt và nó có thể thực hiện thao tác xoay vòng một chút trước khi đưa nó lên trên tôi vào thời điểm này, nhưng dù sao thì điều này vẫn hoạt động !!!

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

Mã kiểm tra dưới đây:

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

Đầu ra:

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

Tôi đang cố gắng để có được sức mạnh thấp hơn gần nhất là 2 và thực hiện chức năng này. Có thể nó giúp bạn. Chỉ cần nhân số thấp nhất gần nhất lần 2 để có được sức mạnh trên gần nhất là 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

Câu trả lời của Paul Dixon cho Excel, điều này hoạt động hoàn hảo.

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

0

Một biến thể của câu trả lời @YannDroneaud hợp lệ cho x==1, chỉ dành cho dạng tấm x86, trình biên dịch, gcc hoặc 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

Đây là những gì tôi đang sử dụng để có một biểu thức không đổi, nếu đầu vào là một biểu thức không đổi.

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

Vì vậy, ví dụ, một biểu thức như:

uptopow2(sizeof (struct foo))

sẽ giảm độc đáo đến một hằng số.



0

Chuyển đổi nó thành một float và sau đó sử dụng .hex () để hiển thị biểu diễn IEEE được chuẩn hóa.

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

Sau đó, chỉ cần giải nén số mũ và thêm 1.

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

Và nâng 2 lên sức mạnh này.

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


Lưu ý câu trả lời này là bằng tră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

Nếu bạn cần nó cho những thứ liên quan đến 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
'cho' là một vòng lặp.
florin

1
florin: nó là và nó được sử dụng như một vòng lặp ở đây, phải không?
Tamas Czinege

9
DrJokepu - Tôi nghĩ rằng florin muốn nói ở đây rằng OP đã yêu cầu một giải pháp không vòng lặp
Eli Bendersky

-1

Nếu bạn muốn một mẫu một dòng. Nó đây rồi

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

hoặc là

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

Đây là hành vi không xác định trong C hoặc C ++ và sẽ dẫn đến lỗi. Sửa đổi nnhiều lần mà không có điểm thứ tự là không hợp lệ. Bạn đã viết nó như thể n-=1sẽ xảy ra đầu tiên nhưng đảm bảo duy nhất ở đây là ncó chứa giá trị mới của nó sau ;và dấu ngoặc đơn không thay đổi điều đó.
sam hocevar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.