我过去几天一直在思考的一个有趣的问题是如何将一个整数的位复制到目标整数中给定位置的另一个整数。因此,例如,给定目标整数0xdeadbeef
和源整数0xabcd
,想法是获得0xabcdbeef
的结果(给定目标位置为16位)或{{ 1}}(给定目标位置为8位)。
由于避免条件或循环的任意限制(允许自己只使用数学/按位运算),我开发了以下函数(C ++)
0xdeabcdef
其中int setbits(int destination, int source, int at, int numbits)
{
int ones = ((1<<(numbits))-1)<<at;
return (ones|destination)^((~source<<at)&ones);
}
是应将源位复制到目标号码(0-31)的位置,at
是从numbits
复制的位数(1- 32)。据我所知,该算法适用于除source
= 0和at
= 32之外的所有值(由于整数目标整数被源整数覆盖的情况) 1 <&lt;&lt; 32导致1(因为移位环绕)而不是0.
我的问题是:
算法设计对我来说通常是一个弱点,所以当我只使用数学/按位运算时,我不知道我的算法是否“尽可能好”。感谢
答案 0 :(得分:5)
除非你编写汇编程序,否则我认为它不会更有效率。
您可以提高可读性并解决您的溢出问题,从而改变一些小事情:
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
}}
答案 1 :(得分:3)
我不认为1&lt;&lt; 32包裹(否则,为什么不&lt;&lt; 31也包裹?),而我认为内部模数32应用于第二个运算符,所以1 <&lt; 32&lt; 32实际上等于1 <&lt; 0。另外,请考虑将参数类型从“int”更改为“unsigned int”。要获得“一”的值而不遇到“1&lt;&lt; 32”问题,您可以这样做:
unsigned int ones = (0xffffffff >> (32-numbits)) << at;
我不相信这种操作有任何“标准”方法。我确信还有其他方法可以以不同的方式使用按位运算符来实现相同的结果,但您的算法与任何算法一样好。
尽管如此,可维护性和文档也很重要。您的函数将受益于使用注释记录的算法,特别是解释您如何使用按位异或 - 这很聪明,但乍一看并不容易理解。
答案 2 :(得分:2)
非常好:我尝试了这个替代版本,但你的测试速度提高了约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);
}
答案 3 :(得分:1)
广义GRB-fnieto形式......
template <typename T>
T setbits4(T destination, T source, int at, int numbits)
{
T mask = (((T)-1)>>(sizeof(T)*8-numbits))<<at; // 4th aproach
return (destination&~mask)|((source<<at)&mask);
}
答案 4 :(得分:0)
我认为它几乎不会更有效率。此外,按位运算比任何代数运算快得多。
答案 5 :(得分:0)
// SET OF FUNCTIONS
//########## BIT - BIT
template < typename var_t > inline var_t bit_V ( uint8_t b ) { return var_t(1) << b; } // Same as usual macros, but this one converts de variable type, so that you can use it in uint8_t to uint64_t for example.
template < typename var_t > inline var_t bit_get ( const var_t & V , uint8_t b ) { return V & bit_V<var_t>(b); } // Can be used as bool or to get the mask of the bit.
template < typename var_t > inline var_t bit_settled ( const var_t & V , uint8_t b ) { return V | bit_V<var_t>(b); }
template < typename var_t > inline var_t bit_unsettled ( const var_t & V , uint8_t b ) { return V &~ bit_V<var_t>(b); }
template < typename var_t > inline void bit_set ( var_t & V , uint8_t b ) { V |= bit_V<var_t>(b); }
template < typename var_t > inline void bit_unset ( var_t & V , uint8_t b ) { V &= ~bit_V<var_t>(b); }
template < typename var_t > inline void bit_mod ( var_t & V , uint8_t b , bool set ) { if (set) bit_set(V,b); else bit_unset(V,b); } // compiler will optimize depending on if 'set' is constant.
template < typename var_t > inline void bit_cpy ( var_t & V , const var_t & S , uint8_t b ) { var_t t = bit_get(S,b); V |= t; V &~ t; }
template < typename var_t > inline void bit_cpy ( var_t & V , const var_t & S , uint8_t bV , uint8_t bM ) { bit_mod(V,bV,bit_get(S,bM)); }
/// MULTIPLE BITS:
template < typename var_t > inline void bits_set ( var_t & V , const var_t & S ) { V |= S; }
template < typename var_t > inline void bits_unset ( var_t & V , const var_t & S ) { V &= ~S; }
/// ONLY WITH UNSIGNED INTS: 'at' parameters are refered to the less significant bit (lsb), starting at 0 index ( a byte would have 7 to 0 bits ).
template < typename var_t > void bits_cpy ( var_t & V , const var_t & S , uint8_t numBits , uint8_t atlsb = 0 ) { // I choosed not to make this one inline
var_t mask = (~var_t(0)>>(sizeof(var_t)*8 - numBits))<<atlsb;
bits_unset ( V , mask ) ;
bits_set ( V , S & mask ) ;
}
template < typename var_t > void bits_cpy ( var_t & V , const var_t & S , uint8_t numBits , uint8_t atVlsb , uint8_t atSlsb ) { // I choosed not to make this one inline
bits_cpy ( V , (atVlsb>atSlsb)?(S<<(atVlsb-atSlsb)):(S>>(atSlsb-atVlsb)) , numBits , atVlsb ) ;
}
template < typename var_t > var_t bits_cpyd ( const var_t & V , const var_t & S , uint8_t numBits , uint8_t atlsb = 0 ) {
var_t r = V;
bits_cpy (r,S,numBits,atlsb);
return r;
}
template < typename var_t > var_t bits_cpyd ( const var_t & V , const var_t & S , uint8_t numBits , uint8_t atVlsb , uint8_t atSlsb ) {
var_t r = V;
bits_cpy (r,S,numBits,atVlsb,atSlsb);
return r;
}
//########## BIT - BIT - EXAMPLE OF USE WITH THE MOST RELEVANT FUNCTIONS:
// I used them inside functions, to get/set two variables inside a class, u and c
void u_set ( edrfu_t u ) { bits_cpy <uint32_t> ( CFG , u , 8 , 2 ,0 );}
edrfu_t u_get () { return bits_cpyd <uint32_t> ( 0 , CFG , 8 , 0 ,2 );}
void c_set ( edrfc_t c ) { bits_cpy <uint32_t> ( CFG , c , 2 );}
edrfc_t c_get () { return bits_cpyd <uint32_t> ( 0 , CFG , 2 );}
答案 6 :(得分:0)
uint32_t的 copy_bits(uint32_t dst,uint32_t src,uint8_t end_bit,uint8_t start_bit)
{
uint32_t left, right, mask, result;
if (end_bit <= start_bit)
{
printf("%s: end_bit:%d shall be greater than start_bit: %d\n", __FUNCTION__, end_bit, start_bit);
return 0;
}
left = ~0; // All Fs
right = ~0;
result = 0;
left >>= ((sizeof(uint32_t)*8) - end_bit); // Create left half of mask
right <<= start_bit; // Create right half of mask
mask = (left & right); // Now you have the mask for specific bits
result = (dst & (~mask)) | (src & (mask));
printf("%s, dst: 0x%08x, src: 0x%08x, end_bit: %d, start_bit: %d, mask: 0x%08x, result: 0x%08x\n",
__FUNCTION__, dst, src, end_bit, start_bit, mask, result);
return result;
}