Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在一个位范围内查找第一个设置位的位置_C_Optimization_Bit Manipulation_Simd_Fixed Point - Fatal编程技术网

C 在一个位范围内查找第一个设置位的位置

C 在一个位范围内查找第一个设置位的位置,c,optimization,bit-manipulation,simd,fixed-point,C,Optimization,Bit Manipulation,Simd,Fixed Point,在我的代码中,我发现处理器将大部分时间花在下面所示的函数上。循环的目标是找出满足循环内条件的val1值。变量Val1和a的类型为long int(64位)。而且,它们是函数内部声明的局部非静态变量 long long int findval(long long int x) { long long int Val1,a=x; for (Val1 = 63; Val1 > 22; Val1--) { if (((a >> Val1) &

在我的代码中,我发现处理器将大部分时间花在下面所示的函数上。循环的目标是找出满足循环内条件的val1值。变量Val1和a的类型为long int(64位)。而且,它们是函数内部声明的局部非静态变量

long long int findval(long long int x)
{

  long long int Val1,a=x;

  for (Val1 = 63; Val1 > 22; Val1--) 
  {
        if (((a >> Val1) & 1) == 1) 
            break;
  }

  return Val1;
}

有没有其他简单/优化的方法来找出Val1值?

首先,请记住,仅仅因为处理器在该函数片段上花费了大部分时间,并不意味着该片段存在问题。也许你应该试着找出为什么你的代码经常调用这个片段

第二,既然你是来寻求帮助的,你不妨向我们展示你所拥有的一切,而不是你所拥有的一部分,你认为这些应该足以让我们找出问题所在。最重要的是,您真的应该准确地向我们展示变量是如何声明的,以及它们声明的确切位置。它们是本地的吗?它们是静态的吗?可能是您将某个东西声明为
volatile
?没有什么是无关紧要的,一切都重要

在任何情况下,如果我们假设代码段可以优化,那么我会说:

您的
Val1
不应
long-long-int
,因为其值仅在23到63之间。因此,它应该是一个
int

(如果出于某种原因,必须将
Val1
计算为
长整型
,则尝试将其强制转换为循环之前类型为
int
的另一个变量,并在循环中使用该变量。)


如果您尝试这样做,那么编译器可能会发现您要做的是找到位范围内的第一个非零位,并用一条机器指令替换整个循环。

首先,请记住,仅仅因为您发现处理器在该函数片段上花费了大部分时间,并不意味着该片段存在问题。也许你应该试着找出为什么你的代码经常调用这个片段

第二,既然你是来寻求帮助的,你不妨向我们展示你所拥有的一切,而不是你所拥有的一部分,你认为这些应该足以让我们找出问题所在。最重要的是,您真的应该准确地向我们展示变量是如何声明的,以及它们声明的确切位置。它们是本地的吗?它们是静态的吗?可能是您将某个东西声明为
volatile
?没有什么是无关紧要的,一切都重要

在任何情况下,如果我们假设代码段可以优化,那么我会说:

您的
Val1
不应
long-long-int
,因为其值仅在23到63之间。因此,它应该是一个
int

(如果出于某种原因,必须将
Val1
计算为
长整型
,则尝试将其强制转换为循环之前类型为
int
的另一个变量,并在循环中使用该变量。)


如果您这样做,编译器可能会发现您要做的是找到位范围内的第一个非零位,并用一条机器指令替换整个循环。

警告:我的答案写错了(第一位在右边),对不起。无论如何,这些方法可以很容易地适应MSb


您可以通过查阅表格的方式缩短流程。您可以为从
0
2^k-1
的所有数字预计算最右边位的索引。您将一次处理
k
位的切片中的数字,然后从右到左尝试切片,直到切片为非零

一个有趣的选择是将long映射到一个8字节的数组;字节对应于256个条目的查找表。这样,您就可以从按字节直接寻址中获益

也可以通过
shorts
进行处理,代价是LUT为65536(64K)个条目。最佳选择可能介于两者之间。有缓存效果


另一个有用的方法是二分法:屏蔽32个高阶位(或加载低
int
)并测试零。然后对于非零部分,屏蔽掉16个高阶位,依此类推。最后,使用LUT技巧。只需3个步骤,您就可以从64个减少到8个


如果位索引的分布是均匀的,则这是合适的。如果偏向于较小的值,顺序搜索可能会更好。

警告:我的答案写错了(第一位在右边),对不起。无论如何,这些方法可以很容易地适应MSb


您可以通过查阅表格的方式缩短流程。您可以为从
0
2^k-1
的所有数字预计算最右边位的索引。您将一次处理
k
位的切片中的数字,然后从右到左尝试切片,直到切片为非零

一个有趣的选择是将long映射到一个8字节的数组;字节对应于256个条目的查找表。这样,您就可以从按字节直接寻址中获益

也可以通过
shorts
进行处理,代价是LUT为65536(64K)个条目。最佳选择可能介于两者之间。有缓存效果


另一个有用的方法是二分法:屏蔽32个高阶位(或加载低
int
)并测试零。然后对于非零部分,屏蔽掉16个高阶位,依此类推。最后,使用LUT技巧。只需3个步骤,您就可以减少
#include <limits.h>
inline
int MSB_position_clamped (long long x)
{
    int maxpos = CHAR_BIT * sizeof(x) - 1;
    x |= 1LL << 22;              // avoid x==0 UB and make clz at least 22
    return maxpos - __builtin_clzll(x);
}
# clang 9.0 -O3 for x86-64 System V
MSB_position_clamped:
        or      rdi, 4194304
        bsr     rax, rdi
        ret