আমি একটি ফাংশন লিখতে চাই যা 2 সংখ্যার নিকটতম পরবর্তী পাওয়ারটি দেয়। উদাহরণস্বরূপ যদি আমার ইনপুটটি 789 হয় তবে আউটপুট 1024 হওয়া উচিত any কোনও লুপ ব্যবহার না করে কেবল কিছু বিটওয়াইস অপারেটর ব্যবহার না করে এটি অর্জনের কোনও উপায় আছে কি?
আমি একটি ফাংশন লিখতে চাই যা 2 সংখ্যার নিকটতম পরবর্তী পাওয়ারটি দেয়। উদাহরণস্বরূপ যদি আমার ইনপুটটি 789 হয় তবে আউটপুট 1024 হওয়া উচিত any কোনও লুপ ব্যবহার না করে কেবল কিছু বিটওয়াইস অপারেটর ব্যবহার না করে এটি অর্জনের কোনও উপায় আছে কি?
উত্তর:
বিট টুইডলিং হ্যাকগুলি পরীক্ষা করুন । আপনার বেস 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++;
অন্যান্য প্রস্থে প্রসারিত হওয়া সুস্পষ্ট হওয়া উচিত।
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)); }
এটি হ'ল আপনি যদি জিসিসি (এবং কলং আমি ভাবি?) ব্যবহার করেন তবে সময়টি গ্রহণ করা বুদ্ধিমানের কাজ হবে চারপাশের সমস্ত বিকল্পের কপি-পেস্ট করার পরিবর্তে সিএলজেডে কল সন্ধান করুন।
x > UINT32_MAX
শাখাবিহীন না থাকলে আচরণের সংজ্ঞা নির্ধারণ করে । এছাড়াও, জিসিসি এবং ক্ল্যাং -mtune=generic
ডিফল্টরূপে ব্যবহার করে (যেমন বেশিরভাগ ডিস্ট্রো করে) তাই আপনার কোডটি lzcnt
x86_64- র নির্দেশে প্রসারিত হবে না - যদি আপনি এর মতো কিছু না ব্যবহার করেন তবে এটি আসলে অনেক ধীর গতিতে (একটি libgcc রুটিন) প্রসারিত হবে -march=native
। সুতরাং আপনার প্রস্তাবিত প্রতিস্থাপনটি অ-বহনযোগ্য, বগি এবং (সাধারণত) ধীর er
next = pow(2, ceil(log(x)/log(2)));
এটি x পেতে আপনি 2 সংখ্যা বাড়িয়েছেন তা খুঁজে বের করে কাজ করে (সংখ্যার লগ নিতে এবং পছন্দসই বেসের লগ দ্বারা ভাগ করুন, আরও উইকিপিডিয়া দেখুন )। তারপরে সিলের সাহায্যে নিকটস্থ পুরো নম্বর পাওয়ার পাওয়ার জন্য এটি গোল করুন।
এটি অন্য কোথাও যুক্ত বিটওয়াইজ পদ্ধতিগুলির চেয়ে আরও সাধারণ উদ্দেশ্য (অর্থাত্ ধীর!) পদ্ধতি, তবে গণিতগুলি জানা ভাল, তাই না?
log(pow(2,29))/log(2)
= 29.000000000000004, সুতরাং ফলাফল 2 29 ফেরতের পরিবর্তে 2 30 হয় I আমার মনে হয় এই কারণেই লগ 2 ফাংশন বিদ্যমান?
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;
}
uint32_t
।
আমি এটিও কাজ করে বলে মনে করি:
int power = 1;
while(power < x)
power*=2;
এবং উত্তরটি হ'ল power
।
power <<= 1
x
খুব বড় হয় (যেমন 2 এর পরবর্তী শক্তির প্রতিনিধিত্ব করার জন্য পর্যাপ্ত বিট নয়)।
আপনি জিসিসি ব্যবহার করেন, তাহলে আপনি কটাক্ষপাত আছে করতে চাইতে পারেন next_pow2 () ফাংশন অপ্টিমাইজ Lockless Inc দ্বারা .. এই পৃষ্ঠাটি ব্যবহার করুন একটি উপায় বর্ণনা বিল্ট-ইন ফাংশন builtin_clz()
(শূন্য COUNT) এবং পরে সরাসরি এক্স 86 ব্যবহার করুন (ia32) assembler নির্দেশ bsr
করো (বিপরীতক্রমে বিট স্ক্যান), ঠিক যেমন বর্ণিত হচ্ছে অন্য উত্তর এর gamedev সাইটের লিংক । এই কোডটি পূর্বের উত্তরে বর্ণিতগুলির চেয়ে দ্রুত হতে পারে ।
যাইহোক, যদি আপনি এসেম্বলারের নির্দেশনা এবং 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));
}
_BitScanForward
ভিজ্যুয়াল সি ++
__builtin_ctz()
__builtin_ctz()
কোনও অ-
constexpr uint64_t nextPowerOfTwo64 (uint64_t x) { return 1ULL<<(sizeof(uint64_t) * 8 - __builtin_clzll(x)); }
আরও একটি, যদিও আমি চক্র ব্যবহার করি, তবে এটি গণিতের অপারেন্ডগুলির চেয়ে অনেক দ্রুত
দুটি "তল" বিকল্পের শক্তি:
int power = 1;
while (x >>= 1) power <<= 1;
দুটি "সিল" বিকল্পের শক্তি:
int power = 2;
x--; // <<-- UPDATED
while (x >>= 1) power <<= 1;
হালনাগাদ
মন্তব্যে যেমন উল্লেখ করা হয়েছে সেখানে ceil
ফলাফল ছিল যেখানে ভুল ছিল mistake
এখানে সম্পূর্ণ ফাংশন রয়েছে:
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;
}
x
2 পাওয়ার হলে ফলাফলটি সঠিক হয় না input ইনপুট 2 এর পাওয়ার হয় কিনা তা পরীক্ষা করতে একটি মাইক্রো। #define ISPOW2(x) ((x) > 0 && !((x) & (x-1)))
if (x == 0) return 1; /* Or 0 (Which is what I use) */ x--; /* Rest of program */
power of two "ceil" option
সঠিক নয়। উদাহরণস্বরূপ, যখন x = 2
2
4
কোনও স্বাক্ষরবিহীন প্রকারের জন্য, বিট টুইডলিং হ্যাকগুলিতে বিল্ডিং:
#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;
}
সংকলকটি পুনরাবৃত্তির সংখ্যা সংকলনের সময়ে জানে বলে সেখানে সত্যিই একটি লুপ নেই।
std::is_unsigned<UnsignedType>::value
কথন।
আইইইই ফ্লোটের জন্য আপনি এই জাতীয় কিছু করতে সক্ষম হবেন।
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));
}
আপনার যদি একটি পূর্ণসংখ্যার সমাধান প্রয়োজন হয় এবং আপনি ইনলাইন সমাবেশটি ব্যবহার করতে সক্ষম হন, বিএসআর আপনাকে x86 এর একটি পূর্ণসংখ্যার লগ 2 দেবে। এটি গণনা করে যে কতগুলি ডান বিট সেট করা আছে, যা সেই সংখ্যার লগ 2 এর ঠিক সমান। অন্যান্য প্রসেসরের একই নির্দেশাবলী রয়েছে (প্রায়শই) যেমন সিএলজেড এবং আপনার সংকলকটির উপর নির্ভর করে আপনার জন্য কাজ করার জন্য কোনও অন্তর্নিহিত উপস্থিত থাকতে পারে।
প্রশ্ন থাকা সত্ত্বেও c
এখানে আমার পাঁচটি সেন্ট ট্যাগ করা আছে। আমাদের ভাগ্যবান, সি ++ 20 এর অন্তর্ভুক্ত হবে std::ceil2
এবং std::floor2
( এখানে দেখুন )। এটি consexpr
টেম্পলেট ফাংশন, বর্তমান জিসিসি বাস্তবায়ন বিটশিফিং ব্যবহার করে এবং যে কোনও অবিচ্ছেদ্য স্বাক্ষরযুক্ত প্রকারের সাথে কাজ করে।
bit_ceil
ওপেন -std.org/JTC1/SC22/WG21/docs/papers/2020/p1956r1.pdf
/*
** 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 এর মধ্যে হতে হবে। সংকলনের সময় ধ্রুবক সেট করতে ম্যাক্রোও দরকারী।
সম্পূর্ণতার জন্য এখানে বগ-স্ট্যান্ডার্ড সি-তে একটি ভাসমান-পয়েন্ট বাস্তবায়ন রয়েছে is
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);
}
rep bsr ecx,eax; mov eax,0; cmovnz eax,2; shl eax,cl
প্রায় 25x দ্রুত।
পূর্ণসংখ্যার ইনপুটটির জন্য সি / সি ++ তে একটি দক্ষ মাইক্রোসফ্ট (যেমন, ভিজ্যুয়াল স্টুডিও 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
স্পষ্টতই ভিজ্যুয়াল স্টুডিও সি ++ সংকলকটি সংকলন-সময়ের মানগুলির জন্য এটি অনুকূলিতকরণের জন্য কোড করা হয়নি তবে এটি পুরোপুরি নির্দেশাবলীর মতো নয় not
সম্পাদনা:
আপনি যদি 1 টি (জিরোথ শক্তিতে 2) উত্পন্ন করতে একটি ইনপুট মান চান, তবে উপরের কোডটিতে একটি ছোট পরিবর্তন এখনও সরাসরি কোনও শাখা ছাড়াই নির্দেশের মাধ্যমে উত্পন্ন করে।
inline unsigned int ExpandToPowerOf2(unsigned int Value)
{
unsigned long Index;
_BitScanReverse(&Index, --Value);
if (Value == 0)
Index = (unsigned long) -1;
return (1U << (Index + 1));
}
আরও কয়েকটি নির্দেশাবলী উত্পন্ন করে। কৌশলটি হ'ল সূচকটি একটি পরীক্ষা দ্বারা প্রতিস্থাপন করা যেতে পারে তারপরে একটি সেমিওভের নির্দেশনা।
এক্স 86 এ আপনি এটি দ্রুত করার জন্য 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
সিতে আপনি ম্যাচিং ইন্টারনিস্টিকগুলি ব্যবহার করতে পারেন।
সিতে আমার সমাধানটি এখানে আশা করি এটি সাহায্য করবে!
int next_power_of_two(int n) {
int i = 0;
for (--n; n > 0; n >>= 1) {
i++;
}
return 1 << i;
}
অনেক প্রসেসরের আর্কিটেকচার সমর্থন log base 2
বা খুব অনুরূপ অপারেশন - count leading zeros
। অনেক সংকলক এর জন্য অন্তর্নিহিত আছে। Https://en.wikedia.org/wiki/Find_first_set দেখুন
ধরে নিচ্ছি আপনার কাছে একটি ভাল সংকলক রয়েছে এবং আমার হাতের উপরে এই মুহুর্তের আগে এটি কিছুটা ঘোরতর কাজ করতে পারে তবে যাইহোক এটি কাজ করে !!!
// 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
আমি 2 এর নিকটতম নিম্ন শক্তি পাওয়ার চেষ্টা করছি এবং এই ফাংশনটি তৈরি করেছি। এটি আপনাকে সহায়তা করতে পারে J নিকটস্থ 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;
}
@YanDroneaud উত্তরের একটি বৈকল্পিক x==1
কেবল x86 প্ল্যাটফর্ম, সংকলক, জিসিসি বা ঝনঝনির জন্য বৈধ :
__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);
}
ইনপুটটি যদি একটি ধ্রুবক অভিব্যক্তি হয় তবে আমি এটি ব্যবহার করতে যাচ্ছি এটি একটি ধ্রুবক প্রকাশ হতে পারে।
#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))
সুন্দরভাবে একটি ধ্রুবক হ্রাস করা হবে।
এটিকে একটি ফ্লোটে রূপান্তর করুন এবং তারপরে .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
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
ওপেনজিএল সম্পর্কিত স্টাফগুলির জন্য আপনার যদি এটির প্রয়োজন হয়:
/* 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;
}
}
আপনি যদি একটি লাইন-টেম্পলেট চান। এটা এখানে
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)); }
n
সিকোয়েন্স পয়েন্ট ব্যতীত একাধিকবার সংশোধন করা অবৈধ। আপনি এটি লিখেছিলেন n-=1
যেন প্রথম হওয়া উচিত তবে এখানে কেবলমাত্র গ্যারান্টিটি হ'ল n
এতে ;
এবং এর প্রথম বন্ধনীর পরে এটির নতুন মান রয়েছে that