用于从一个int到另一个int的任意位置复制N位的算法
过去几天我一直在思考的一个有趣问题是如何将一个整数的位复制到目标整数给定位置处的另一个整数中。 因此,例如,给定目标整数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);
}
其中at
是应将源位复制到目标编号(0-31)中的位置,而numbits
是从source
(1-32)复制的位数。 据我所知,此算法适用于除at
= 0和numbits
= 32(整个目标整数被源整数覆盖的情况)之外的所有值,这是由于1 << 32导致1 (因为换档环绕)而不是0。
我的问题是:
算法设计对我来说通常是一个弱点,所以我不知道只使用数学/按位运算时,我的算法是否“尽可能好”。 谢谢
我不认为1 << 32包装(否则,为什么不是2 << 31也包装?),而是我认为内部模数32应用于第二个运算符,所以1 << 32实际上相当于1 << 0。 另外,考虑将参数类型从“int”更改为“unsigned int”。 要获得“ones”的值而不会遇到“1 << 32”问题,可以这样做:
unsigned int ones = (0xffffffff >> (32-numbits)) << at;
我不相信这种操作有任何“标准”方法。 我确信还有其他方法可以以不同的方式使用按位运算符来实现相同的结果,但是您的算法与任何方法一样好。
尽管如此,可维护性和文档也很重要。 您的功能可以从记录了评论的算法中受益,特别是解释如何使用按位异或 - 这很聪明,但乍看起来不易理解。
除非您编写汇编程序,否则我认为不会更高效。
你可以提高可读性并解决你的溢出问题,改变一些小东西:
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);
}
更高效的汇编程序版本(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
}}
它非常好:我尝试了这个替代版本,但你的测试速度快了大约30%:
int[] bits = new int[] {0,1,3,7,15,31,63,127,255,511,1023
,2047,4095,8192,16383,32767,65535,131071,262143,524287
,1048575,2097151,4194303,8388607,16777215,33554431,67108863
,134217727,268435455,536870911,1073741823,2147483647,-1};
public int setbits2(int destination, int source, int at, int numbits)
{
int ones = bits[numbits + at] & ~bits[at];
return (destination & ~ones) | ((source << at) & ones);
}
链接地址: http://www.djcxy.com/p/37289.html
上一篇: Algorithm for copying N bits at arbitrary position from one int to another