2011-03-09 93 views
12

我正在使用僅按位運算符在C中創建邏輯右移函數。下面是我有:在C中實現邏輯右移C

int logical_right_shift(int x, int n) 
{ 
    int size = sizeof(int); // size of int 

    // arithmetic shifts to create logical shift, return 1 for true 
    return (x >> n) & ~(((x >> (size << 3) - 1) << (size << 3) -1)) >> (n-1); 
} 

這實際上適用於所有案件,但如果n = 0,我一直在試圖找出一個辦法來解決它,所以它會爲N功= 0爲好,但我卡住了。

+2

你正在做一個邏輯右移運營商簽署的類型? – 2011-03-09 22:43:32

+0

if(n == 0){return x; ''? – 2011-03-09 22:45:36

+0

使用@Mark的建議,你可以改變它爲此(不保證它的工作原理):'return(n == 0?x:(x >> n)&〜(((x >>(size << 3 ) - 1)<<(size << 3) -1)) >>(n-1));' – 2011-03-09 22:47:41

回答

23
int lsr(int x, int n) 
{ 
    return (int)((unsigned int)x >> n); 
} 
+2

這是正確的答案(對結果進行不必要和醜陋的模型模)。負值的右移具有實現定義的行爲(或者是實現定義的行爲值?我忘記了),所以在使用帶有符號值的'>>'運算符的任何'lsr'函數的實現都是不可移植的。 – 2011-03-09 23:12:53

+0

這個解決方案的一個問題:嚴格地說,它在'n == 0'的情況下具有實現定義的行爲,因爲從int到'unsigned'的轉換和返回導致實現定義的行爲,如果原始值是負。第一次轉換必須以'UINT_MAX + 1'爲模發生,但是轉換回帶符號的'int'可能只是對錶示的重新解釋,在這種情況下,值將被改變。 – 2011-03-09 23:14:42

0

與@伊格納西奧的評論,我不知道爲什麼你會想這樣做(不需要像在其他答案中一樣對unsigned進行強制轉換),但是怎麼樣(假設二進制補碼和二進制,以及有符號移位是算術運算):

(x >> n) + ((1 << (sizeof(int) * CHAR_BIT - n - 1)) << 1) 

或:

(x >> n)^((INT_MIN >> n) << 1) 
2

我認爲問題出在你的 「>>(N-1)」 的一部分。如果n是0,那麼左邊的部分將被移動-1。 所以,這裏是我的解決方案

int logical_right_shift(int x, int n) 
{ 
    int mask = ~(-1 << n) << (32 - n); 
    return ~mask & ((x >> n) | mask); 
} 
10

這是你所需要的:

int logical_right_shift(int x, int n) 
{ 
    int size = sizeof(int) * 8; // usually sizeof(int) is 4 bytes (32 bits) 
    return (x >> n) & ~(((0x1 << size) >> n) << 1); 
} 

解釋

x >> n轉變n bits權。但是,如果x爲負,符號位(最左邊的位)將被複制到它的權利,例如:

假設每個int是32位這裏,讓
x     = -2147483648 (10000000 00000000 00000000 00000000),然後
x >> 1 = -1073741824 (11000000 00000000 00000000 00000000)
x >> 2 = -536870912  (11100000 00000000 00000000 00000000)
等等。

因此,當n爲負時,我們需要清除那些符號額外符號位。

假設n = 5這裏:

0x1 << size移動1到最左邊的位置:

(10000000 00000000 00000000 00000000)

((0x1 << size) >> n) << 1複印1到其n-1鄰居:

(11111000 00000000 00000000 00000000)

~((0x1 << size) >> n) << 1!反轉所有位:

(00000111 11111111 11111111 11111111)

,所以我們最終得到的是面膜,以提取真正需要從x >> n

(x >> n) & ~(((0x1 << size) >> n) << 1) 

&操作做的伎倆。

並且該功能的總成本是6操作。

+1

我認爲這是正確的。但是,你可以做32次左移嗎?這將是一個未定義的轉變? – 2013-08-17 05:13:10

+2

是的,如果'int'是例如4個字節,則失敗。他需要從'size'中減去1,這樣如果'int'是4個字節,'size'是31. – modulitos 2014-07-25 02:29:21

0

Milnex的回答非常好,並有一個很棒的解釋,但不幸的是,由於整體大小的變化,執行失敗。這是一個工作版本:

int logicalShift(int x, int n) { 
    int totalBitsMinusOne = (sizeof(int) * 8) - 1; // usually sizeof(int) is 4 bytes (32 bits) 
    return (x >> n) & ~(((0x1 << totalBitsMinusOne) >> n) << 1); 
} 

有1個爲最顯著位,和所有其他地方的零,我們需要number of bits - 1轉移0x1。我正在提交自己的答案,因爲我接受的答案的編輯被拒絕了。

0
int logicalShift(int x, int n) { 
    int mask = x>>31<<31>>(n)<<1; 
    return mask^(x>>n); 
} 

僅適用於32位

+2

請添加更多信息來解釋您的答案。在這裏,僅有代碼的答案不被接受。 – 2017-01-22 23:49:48

+1

@MarkYisri Ironic因爲這個「線程」的頂級投票答案是代碼而且完全清楚地回答了這個問題。 – 2017-09-27 01:46:04