如何高效地计算给定数字的最大2的幂次,该幂次小于或等于给定数字?
如何高效地计算给定数字的最大2的幂次,该幂次小于或等于给定数字?
到目前为止,我提出了三个解决方案:\n极低效的标准库函数pow
和log2
:\n
int_fast16_t powlog(uint_fast16_t n) { return static_cast(pow(2, floor(log2(n)))); }
\n效率更高的连续计算2的幂,直到达到比所需的更大的数:\n
uint_fast16_t multiply(uint_fast16_t n) { uint_fast16_t maxpow = 1; while(2*maxpow <= n) maxpow *= 2; return maxpow; }
\n到目前为止最有效的方法是在预计算的2的幂表中进行二分查找:\n
uint_fast16_t binsearch(uint_fast16_t n) { static arraypows {1,2,4,8,16,32,64,128,256,512, 1024,2048,4096,8192,16384,32768,65536,131072,262144,524288}; return *(upper_bound(pows.begin(), pows.end(), n)-1); }
\n还可以进一步优化吗?这里有什么技巧可以使用吗?\n我使用的完整基准测试如下:\n
#include#include #include #include #include #include using namespace std; using namespace chrono; uint_fast16_t powlog(uint_fast16_t n) { return static_cast (pow(2, floor(log2(n)))); } uint_fast16_t multiply(uint_fast16_t n) { uint_fast16_t maxpow = 1; while(2*maxpow <= n) maxpow *= 2; return maxpow; } uint_fast16_t binsearch(uint_fast16_t n) { static array pows {1,2,4,8,16,32,64,128,256,512, 1024,2048,4096,8192,16384,32768,65536,131072,262144,524288}; return *(upper_bound(pows.begin(), pows.end(), n)-1); } high_resolution_clock::duration test(uint_fast16_t(powfunct)(uint_fast16_t)) { auto tbegin = high_resolution_clock::now(); volatile uint_fast16_t sink; for(uint_fast8_t i = 0; i < UINT8_MAX; ++i) for(uint_fast16_t n = 1; n <= 999999; ++n) sink = powfunct(n); auto tend = high_resolution_clock::now(); return tend - tbegin; } int main() { cout << "Pow and log took " << duration_cast (test(powlog)).count() << " milliseconds." << endl; cout << "Multiplying by 2 took " << duration_cast (test(multiply)).count() << " milliseconds." << endl; cout << "Binsearching precomputed table of powers took " << duration_cast (test(binsearch)).count() << " milliseconds." << endl; }
\n在我的笔记本电脑上使用-O2
编译后,得到以下结果:\n
Pow and log took 19294 milliseconds. Multiplying by 2 took 2756 milliseconds. Binsearching precomputed table of powers took 2278 milliseconds.
问题的原因:
这个问题的出现是因为需要找到一个给定数的最高的小于等于它的2的幂次方。
解决方法:
下面是一种有效的方法来计算小于等于给定数的最高2的幂次方。首先,检查给定数是否小于2,如果是,则返回1作为结果。接下来,使用一个变量maxpow来存储当前的幂次方,初始化为1。如果给定数大于256,那么maxpow被设置为256乘以128,这样可以更快地接近给定数,并且可以快速修正超出范围的情况。然后,使用一个循环来不断将maxpow右移两位,直到maxpow大于给定数为止,这样可以修正低估的情况。接下来,使用另一个循环来不断将maxpow乘以2,直到2倍的maxpow大于等于给定数为止,这样可以修正高估的情况。最后,返回maxpow作为结果。
这段代码可能适用于32位变量,可以使用65k的常量字面量代替256。
文章整理:
如何高效地计算小于等于给定数的最高2的幂次方?
这个问题的出现是因为需要找到一个给定数的最高的小于等于它的2的幂次方。
下面是一种有效的方法来计算小于等于给定数的最高2的幂次方。首先,检查给定数是否小于2,如果是,则返回1作为结果。接下来,使用一个变量maxpow来存储当前的幂次方,初始化为1。如果给定数大于256,那么maxpow被设置为256乘以128,这样可以更快地接近给定数,并且可以快速修正超出范围的情况。然后,使用一个循环来不断将maxpow右移两位,直到maxpow大于给定数为止,这样可以修正低估的情况。接下来,使用另一个循环来不断将maxpow乘以2,直到2倍的maxpow大于等于给定数为止,这样可以修正高估的情况。最后,返回maxpow作为结果。
如果需要适用于32位变量,可以使用65k的常量字面量代替256。
如何高效地计算小于或等于给定数字的最高2的幂次方?
有人提出了如何更高效地解决这个问题的想法,并且通过对标准库二分查找进行改进来实现了这个目标。他们使用了一个查找表来优化二分查找的速度,然后测试了不同方法的性能。
首先,他们通过使用一个选择函数来优化二分查找的速度。选择函数的作用是根据给定的值和查找表中的元素值来选择返回的索引值。他们还使用了一个快速上界函数来实现二分查找。
通过使用这个改进后的二分查找函数,他们发现性能有了显著的提升。他们进行了一系列基准测试,发现使用这个函数的性能比使用其他方法要好很多。
接下来,他们提出了进一步优化选择函数的想法。他们使用了x86_64汇编语言来实现选择函数,进一步提高了性能。他们通过内联汇编语言来实现这个函数,并使用了条件移动指令来选择返回的索引值。
通过使用这个优化后的选择函数,他们再次进行了基准测试,并发现性能又有了显著的提升。他们发现使用这个优化后的选择函数比使用其他方法要快很多。
最后,他们讨论了一些其他的优化方法。其中一个方法是使用位运算来计算最高的设置位,并将1左移该位数。他们还讨论了不同计算机和操作系统的差异对性能的影响。
这篇文章介绍了如何高效地计算小于或等于给定数字的最高2的幂次方。通过使用查找表、优化二分查找函数和使用汇编语言来优化选择函数,可以显著提高性能。通过对不同方法进行基准测试,可以找到最佳的解决方案。
如何高效计算给定数的小于或等于给定数字的最高2的幂次的问题?
这个问题的出现是因为有人想要找到一个高效的方法来计算给定数字的最高2的幂次。下面是一些解决方法:
1. 使用位运算符的解决方法:
uint32_t highestPowerOfTwoIn(uint32_t x) { x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x ^ (x >> 1); }
这个方法首先将最高位的1向右扩展,然后通过 `x ^ (x >> 1)` 保留与其左侧位不同的位(最高位被认为是左侧的0),这些位只有最高位的1,因为通过扩展,数的形式为 0n1m。
2. 使用内置函数的解决方法:
uint32_t highestPowerOfTwoIn(uint32_t x) { return 0x80000000 >> __builtin_clz(x); }
或者
uint32_t highestPowerOfTwoIn(uint32_t x) { unsigned long index; _BitScanReverse(&index, x); return 1u << index; }
这两种方法使用了编译器内置的函数来计算最高2的幂次,当目标硬件直接支持时,应该更高效。
3. 如果硬件支持快速的位反转操作,可以使用位反转来计算最高2的幂次:
uint32_t highestPowerOfTwoIn(uint32_t x) { x = _rbit(x); return _rbit(x & -x); }
这个方法利用了位反转操作来找到最高位的1。
总结起来,这些方法提供了多种高效计算最高2的幂次的方式,具体使用哪种方法取决于实际需求和硬件支持情况。