GRB*_*GRB 14 c++ algorithm bit-manipulation
我过去几天一直在思考的一个有趣的问题是如何将一个整数的位复制到目标整数中给定位置的另一个整数.因此,例如,给定目标整数0xdeadbeef和源整数0xabcd,想法是获得0xabcdbeef(给定目标位置为16位)或0xdeabcdef(给定8位的目标位置)的结果.
由于避免条件或循环的任意限制(允许自己只使用数学/按位运算),我开发了以下函数(C++)
int setbits(int destination, int source, int at, int numbits)
{
int ones = ((1<<(numbits))-1)<<at;
return (ones|destination)^((~source<<at)&ones);
}
Run Code Online (Sandbox Code Playgroud)
其中at是其中源位应该被复制到目的地号码(0-31)和地方numbits是被复制的比特数source(1-32).据我所知,这个算法适用于除at= 0和numbits= 32 之外的所有值(整个目标整数被源整数覆盖的情况),因为1 << 32导致1(从转移包裹)而不是0.
我的问题是:
算法设计对我来说通常是一个弱点,所以当我只使用数学/按位运算时,我不知道我的算法是否"尽可能好".谢谢
除非你编写汇编程序,否则我认为它不会更有效率.
您可以提高可读性并解决您的溢出问题,从而改变一些小事:
int setbits2(int destination, int source, int at, int numbits)
{
// int mask = ((1LL<<numbits)-1)<<at; // 1st aproach
int mask = ((~0u)>>(sizeof(int)*8-numbits))<<at; // 2nd aproach
return (destination&~mask)|((source<<at)&mask);
}
Run Code Online (Sandbox Code Playgroud)
更高效的汇编程序版本(VC++):
// 3rd aproach
#define INT_SIZE 32;
int setbits3(int destination, int source, int at, int numbits)
{ __asm {
mov ecx, INT_SIZE
sub ecx, numbits
or eax, -1
shr eax, cl
mov ecx, at
shl eax, cl // mask == eax
mov ebx, eax
not eax
and eax, destination
mov edx, source
shl edx, cl
and edx, ebx
or eax, edx
}}
Run Code Online (Sandbox Code Playgroud)
我不认为 1<<32 会换行(否则,为什么 2<<31 也不换行?),相反,我认为内部模数 32 应用于第二个运算符,因此 1<<32实际上相当于 1<<0。另外,请考虑将参数类型从“int”更改为“unsigned int”。要获取“ones”的值而不遇到“1<<32”问题,您可以这样做:
unsigned int ones = (0xffffffff >> (32-numbits)) << at;
Run Code Online (Sandbox Code Playgroud)
我不相信这种操作有任何“标准”方法。我确信还有其他方法可以以不同的方式使用按位运算符来实现相同的结果,但您的算法与任何算法一样好。
尽管如此,可维护性和文档也很重要。您的函数将受益于用注释记录的算法,特别是解释如何使用按位异或——这很聪明,但乍一看并不容易理解。