在二进制数字中找到第一个位
finding the first set bit in a binary number
我需要在二进制数字从右到左的二进制数字中找到第一个集位;我想出了这个解决方案:
int cnt=0;
while (number& 1 ==0)
{
cnt++;
number>>=1;
}
有更好的方法吗?一些聪明的位操纵技术?
处理器可能具有直接查找的指令:
Windows/MSVC:
- _bitscanforward()
- _bitscanreverse()
GCC:
- __内置_FFS()
- __内置_ctz()
- __ hindin_clz()
这些通常直接映射到本机硬件说明。因此,它不会比这些更快。
,由于没有C/C 功能,因此仅通过编译器内在访问它们。
您可以手动这样做:
n & (n - 1)
是一种删除最右设置位的技术。
所以,n - (n & n - 1)
将仅返回一个只有最右图位的数字。
然后结果的" log2"给出了解决方案:此链接可能会有所帮助
您可以与所有1 << k
一起使用开关盒,将为您提供解决方案
switch (n - (n & n - 1)) {
case 0: ...
case 1 << 0: return 0;
case 1 << 1: return 1;
...
}
如果您希望它快速,则是BITSCAN指令(bsf
,bsr
)或ditwiddling Hack是目标。
编辑:使用开关案例表来提高性能的想法只是未成熟的。
bit twidddling hacks提供了出色的,er,位twiddling hacks,并附有性能/优化讨论。对于您的问题(来自该站点),您可以使用乘法策略:
unsigned int c = number; // your input number
int r; // result goes here
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((c & -c) * 0x077CB531U)) >> 27];
您的代码
int cnt=0;
while (number& 1 ==0)
{
cnt++;
number>>=1;
}
有一个错误。例如,如果数字等于0,则循环将是无限的。
我会以以下方式重写
int cnt = 0;
if ( number ) while ( !( number & ( 1 << cnt++ ) ) );
在这种情况下,如果数字不等于0,则集合位的位置(CNT)将从1开始计数。否则,位置将等于0。
我不确定接受的答案是否正确。我刚刚测试了幼稚的回路与(num&amp; -num)解决方案。它们都是相同的速度。幼稚的循环少得多。我构建了:
gcc 4.7.2从mingw,获胜7gcc test.c -o test.exe -std = c99 -wall -o2
这是我的代码(它可能有一些角案错误,但我怀疑时间大致有效)。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_NUMS 65536
int find_first_bits(unsigned nums[NUM_NUMS])
{
int total = 0; // Prevent compiler from optimizing out the code
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < NUM_NUMS; i++) {
switch (nums[i] & -nums[i]) {
case (1<<0): total += 1; break;
case (1<<1): total += 2; break;
case (1<<2): total += 3; break;
case (1<<3): total += 4; break;
case (1<<4): total += 5; break;
case (1<<5): total += 6; break;
case (1<<6): total += 7; break;
case (1<<7): total += 8; break;
case (1<<8): total += 9; break;
case (1<<9): total += 10; break;
case (1<<10): total += 11; break;
case (1<<11): total += 12; break;
case (1<<12): total += 13; break;
case (1<<13): total += 14; break;
case (1<<14): total += 15; break;
case (1<<15): total += 16; break;
case (1<<16): total += 17; break;
case (1<<17): total += 18; break;
case (1<<18): total += 19; break;
case (1<<19): total += 20; break;
case (1<<20): total += 21; break;
case (1<<21): total += 22; break;
case (1<<22): total += 23; break;
case (1<<23): total += 24; break;
case (1<<24): total += 25; break;
case (1<<25): total += 26; break;
case (1<<26): total += 27; break;
case (1<<27): total += 28; break;
case (1<<28): total += 29; break;
case (1<<29): total += 30; break;
case (1<<30): total += 31; break;
case (1<<31): total += 32; break;
}
}
}
return total;
}
int find_first_bits2(unsigned nums[NUM_NUMS])
{
int total = 0; // Prevent compiler from optimizing out the code
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < NUM_NUMS; i++) {
unsigned mask = 1;
for (int cnt = 1; cnt <= 32; cnt++, mask <<= 1) {
if (nums[i] & mask) {
total += cnt;
break;
}
}
}
}
return total;
}
int main() {
// Create some random data to test
unsigned nums[NUM_NUMS];
for (int i = 0; i < NUM_NUMS; i++) {
nums[i] = rand() + (rand() << 15);
}
clock_t start_time, end_time;
int result;
start_time = clock();
result = find_first_bits(nums);
end_time = clock();
printf("Time = %.5f, result = %dn", (end_time - start_time) / (double)(CLOCKS_PER_SEC), result);
start_time = clock();
result = find_first_bits2(nums);
end_time = clock();
printf("Time = %.5f, result = %dn", (end_time - start_time) / (double)(CLOCKS_PER_SEC), result);
}
- 为什么有时我输入一个整数,程序将第一个输入的数字打印成十进制数?
- 代码以查找数组中的最大数字,但它仅将第一个数字显示为最大数字. 有人请告诉我为什么
- 我必须更改我的数字最后一个数字和第一个数字,但不要使用仅带有整数或循环的函数.例如从 12345 到 52341
- 删除C++中向量中第一个最小的数字(并保持顺序)
- 为什么字符串流只读取整数中的第一个数字?如何使它只在空白处移动?
- 从文件的一行中查找数字的平均值,避免使用第一个单词
- 说单精度碰撞的第一个数字是 131072.02 是否正确?(阳性,将 2 位数字视为尾数)
- 如何在 c++ 中将第一个数字移动到数字的末尾
- 第一个和第二个数字之间能被 4 和 6 整除的所有整数的总和
- C 搜索算法第一个数字= n
- c `digits10`为IEEE float为6,但第一个不可替代的整数已经具有8位数字
- 为什么我的数组只接受它们中的第一个数字
- C++ - 查找数组中第一个和最后一个负数之间的数字
- 给定一个数字n,打印序列中大于或等于n的第一个数字
- 如何从文件中获取数字行并忽略第一个数字
- 打印由用户定义的数组,第一个数字确定单词的大小,第二个数字确定行的大小
- SIFT的OpenCV编号曾经作为第一个关键点数字匹配
- 计算输入数字的次数,直到输入第一个对称数字
- 找出一个特定整数有多少个二进制数字
- 修改我的代码中两个二进制数字的加法