2009-08-16 43 views
14

過去幾天我一直在思考的一個有趣問題是如何將一個整數位複製到目標整數給定位置處的另一個整數。因此,舉例來說,給定目標整數0xdeadbeef和源整數0xabcd,該想法將得到0xabcdbeef(給定目標位置16位)或0xdeabcdef(給定目標位置8位)的結果。從一個int到另一個int的任意位置複製N位的算法

以避免條件句或環中的任意的限制(允許自己使用只是數學/位操作),我開發下面的函數(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導致1 (因爲移回繞到),而不是0

我的問題是:

  1. 這是如何正常進行?有沒有特別值得注意的算法(值得注意的是,我問是否有任何特別有效的技巧可以用來做到這一點)?
  2. 我的算法和我認爲的一樣嗎(也就是說,除了= 0和numbits = 32之外的所有值都適用)?
  3. 與1)相關,是否有任何方法只使用數學/位運算符來做到這一點?所有值的算法使用條件或循環是微不足道的,所以我對此不感興趣。

算法設計對我來說通常是一個弱點,所以我不知道我的算法在使用數學/按位運算時是否「像它得到的一樣好」。謝謝

+1

這很漂亮!我偶爾需要在每個循環計數的環境中操作奇數大小的位串 - 我一定會將其添加到我的一攬子技巧中。 – 2009-08-16 03:53:34

+0

我應該告誡,我只做了一些膚淺的測試,所以我不能保證這種方法能夠100%地工作。 – GRB 2009-08-16 04:07:52

+1

使用unsigned int可以更安全地避免任何有符號位的有趣商業。 – 2009-08-16 06:12:24

回答

3

我不認爲它的情況下1個< < 32包裝(否則,爲什麼沒有按't 2 < < 31也包裝?),而是我認爲內部模數32應用於第二個運算符,因此實際上等於1 < < 0另外,請考慮將參數類型從「int 「到」unsigned int「。要獲得「個位」的值,而不跑步進入「1 < < 32」的問題,你可以這樣做:

unsigned int ones = (0xffffffff >> (32-numbits)) << at; 

我不相信有對於這種操作的任何「標準」的方法。我確信還有其他方法可以以不同的方式使用按位運算符來實現相同的結果,但是您的算法與任何方法一樣好。

儘管如此,可維護性和文檔也很重要。您的功能可以從記錄了評論的算法中受益,特別是解釋如何使用按位異或 - 這很聰明,但乍看起來不易理解。

+0

這取代了'numbits == 0'的問題,其中'numbits == 32'的一個問題,但是因爲它不會有很多意義,它可以被排除在外來自該函數的允許域。 – caf 2009-08-16 10:20:38

+0

你說得對,「換行」可能是錯誤的選擇。我的意思是指執行的內部模量操作(你提到的)。 – GRB 2009-08-16 14:21:10

+2

該解決方案依賴於體系結構。將0xffffffff替換爲〜0(無成本,編譯時間),而32則由您希望支持的體系結構定義的宏INT_SIZE替換。 – 2009-08-16 22:46:56

0

我認爲它幾乎不會更有效率。而且,按位運算比任何代數運算要快得多。

+0

我認爲你在兩點上都是錯的。它可以更高效(請參閱我的答案),至少加法和減法的執行速度與我所知道的每個拱門上的按位運算速度相同。 – hirschhornsalz 2009-08-16 10:15:50

+1

你例句中斷了。 – Havenard 2009-08-16 18:02:06

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); 
    } 
+0

該表可能會更有意義在十六進制 – 2016-04-05 02:47:03

5

我不認爲它可以做得更有效率,除非你編寫彙編器。

可以提高程序的可讀性和解決您的溢出問題改變一些小東西:在32位架構較慢:

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日的aproach
  • 第二個問題:(〜0u)和(sizeof(int)* 8)在編譯時計算,所以它們不收取任何費用。
  • 第3個問題:你節省了3個操作數(內存訪問)把它寫在彙編程序中,但是如果你想使它變得可移植,你將需要編寫ifdefs。
+0

在32位體系結構中,這會帶來性能問題。他沒有要求一個代碼美容師或解決「溢出問題」,如果該功能只用於numbits <32,甚至可能不存在。 他確實要求更快的版本。 – hirschhornsalz 2009-08-16 10:24:51

+0

首先,你甚至讀過我的第一句話嗎?其次,你在哪裏讀過的函數只用於numbits <32? 「numbits是從源(1-32)複製的位數」。第三,可讀性是編寫算法時的基礎,並且只是一個建議。確實,在32位體系結構中有一點性能受到影響,但與公認的解決方案相反,它是體系結構可移植的。 – 2009-08-16 19:35:15

+0

我更新了一個優化的解決方案(第二個aproach) – 2009-08-16 23:38:36

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); 
} 
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 );} 
+0

它被測試,但任何改進都是值得歡迎的。任何關於內聯或不是最終「大」功能的消息? – Anr 2014-10-01 22:17:32

+0

關於表現,我認爲它等同於之前提出的。也許bits_cpy比較快一點,因爲它只需要四次操作(不包括掩碼),而不是五次。 – Anr 2014-10-01 22:26:45

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; 

}

+0

如果你解釋它,你的答案會更有意義。 – 2016-04-05 02:43:56

相關問題