C语言 在 C 中实现逻辑右移

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5253194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:00:54  来源:igfitidea点击:

Implementing Logical Right Shift in C

cbit-manipulation

提问by Dan

I'm working on making a logical right shift function in C using only bitwise operators. Here's what I have:

我正在仅使用按位运算符在 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);
}

This actually works for all cases except if n = 0. I've been trying to figure out a way to fix it so it will work for n = 0 as well, but I'm stuck.

这实际上适用于所有情况,除非 n = 0。我一直试图找出一种方法来解决它,因此它也适用于 n = 0,但我被卡住了。

回答by Ignacio Vazquez-Abrams

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

回答by mingyc

This is what you need:

这是你需要的:

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

Explain

解释

x >> nshifts n bitsright. However, if xis negative, the sign bit (left-most bit) will be copied to its right, for example:

x >> nn bits权。但是,如果x是负数,符号位(最左边的位)将被复制到它的右边,例如:

Assume every int is 32 bitshere, let
x     = -2147483648 (10000000 00000000 00000000 00000000), then
x >> 1 = -1073741824 (11000000 00000000 00000000 00000000)
x >> 2 = -536870912  (11100000 00000000 00000000 00000000)
and so on.

假设这里的每个 int 都是32 位, let
x     = -2147483648 (10000000 00000000 00000000 00000000), then
x >> 1 = -1073741824 (11000000 00000000 00000000 00000000)
x >> 2 = -536870912  (11100000 00000000 00000000 00000000)
等等。

So we need to erase out those sign extra sign bits when n is negative.

因此,当 n 为负时,我们需要擦除那些符号额外的符号位。

Assume n = 5here:

假设n = 5这里:

0x1 << sizemoves 1to the left-most position:

0x1 << size移动1到最左边的位置:

(10000000 00000000 00000000 00000000)

(10000000 00000000 00000000 00000000)

((0x1 << size) >> n) << 1copies 1 to its n-1neighbors:

((0x1 << size) >> n) << 1将 1 复制到其n-1邻居:

(11111000 00000000 00000000 00000000)

(11111000 00000000 00000000 00000000)

~((0x1 << size) >> n) << 1!reverses all bits:

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

(00000111 11111111 11111111 11111111)

(00000111 11111111 11111111 11111111)

so we finally obtain a mask to extract what really need from x >> n:

所以我们最终获得了一个面具来提取真正需要的东西x >> n

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

the &operation does the trick.

&操作是卓有成效的。

And the total cost of this function is 6operations.

而这个功能的总成本是6操作。

回答by Bernd Elkemann

Just store your intin an unsigned int, and perform >>upon it.

只需将您的存储在intunsigned int,然后对其执行>>

(The sign is not extended or preserved if you use unsigned int)

(如果使用 unsigned int,则不会扩展或保留符号)

http://en.wikipedia.org/wiki/Logical_shift

http://en.wikipedia.org/wiki/Logical_shift

回答by Levenson

I think problem is in your ">> (n-1)" part. If n is 0 then left part will be shift by -1. So,here is my solution

我认为问题出在您的“>> (n-1)”部分。如果 n 为 0,则左侧部分将移动 -1。所以,这是我的解决方案

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

回答by Ghulam Murtaza

Derived from php's implementation of logical right shifting

源自php对逻辑右移的实现

function logical_right_shift( i , shift ) {

    if( i & 2147483648 ) {
        return ( i >> shift ) ^ ( 2147483648 >> ( shift - 1 ) );
    }

    return i >> shift;
}

For 32bit platforms only.

仅适用于 32 位平台。

回答by modulitos

Milnex's answer is great and has an awesome explanation, but the implementation unfortunately fails due to the shift by total size. Here is a working version:

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

To have 1 as the most significant bit, and all zeroes elsewhere, we need to shift 0x1by number of bits - 1. I am submitting my own answer because my edit to the accepted answer was somehow rejected.

有1个为最显著位,和其他地方都是零,我们需要转变0x1number of bits - 1。我正在提交我自己的答案,因为我对已接受答案的编辑以某种方式被拒绝。

回答by Toch

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

Only for 32 bits

仅适用于 32 位

回答by Jeremiah Willcock

As with @Ignacio's comment, I don't know why you would want to do this (without just doing a cast to unsignedlike in the other answers), but what about (assuming two's complement and binary, and that signed shifts are arithmetic):

与@Ignacio 的评论一样,我不知道您为什么要这样做(而不仅仅是unsigned在其他答案中进行强制转换),但是呢(假设二进制补码和二进制,并且带符号的移位是算术):

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

or:

或者:

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