【问题标题】:Swap two bits in given integer交换给定整数中的两位
【发布时间】:2021-10-28 20:02:33
【问题描述】:

我看到了一些解决方案,但看起来很复杂。

在 n,m 个位置的两个位之间交换最有效的方法是什么?

int swapBits(int num, int nPostion, int mPosition);

【问题讨论】:

  • 检查这个:Link 1
  • 为什么交换两位的函数需要int num
  • 取 int ,交换两位数并在交换后返回新数

标签: c bit-manipulation byte bitwise-operators bit


【解决方案1】:

给定整数 n,我们希望在其中交换位置 p1 和 p2 的位: 算法:如果两个位相同,则返回相同的值,否则使用 XOR 切换两个位。

unsigned int swapBits(unsigned int n, unsigned int p1, unsigned int p2)
{
  return (((n >> p1) & 1) == ((n >> p2) & 1) ? n : ((n ^ (1 << p2)) ^ (1 << p1)));
}

【讨论】:

  • 如果p2unsigned int 的宽度小一,(1 &lt;&lt; p2) 应该是(1U &lt;&lt; p2) 以避免未定义的行为。 (1 &lt;&lt; p1) 的备注相同
【解决方案2】:

不确定它是否最有效,但我认为这是一个相当简单的解决方案:

int bitValue(int num, int nPosition)
{
    return ( num >> nPosition ) % 2;
}

int swapBits(int num, int nPosition, int mPosition)
{
    int nVal = bitValue(num, nPosition);
    int mVal = bitValue(num, mPosition);

    if (nVal != mVal)
    {
        if (1 == nVal)
        {
           num -= 1<<nPosition;
           num += 1<<mPosition;
        }
        else
        {
            num += 1<<nPosition;
            num -= 1<<mPosition;
        }
    }

    return num;
}

以更高效(但可读性较差)的方式提供相同的解决方案:

int swapBits2(int num, int nPosition, int mPosition)
{
    int nVal = ( num >> nPosition ) % 2;
    int mVal = ( num >> mPosition ) % 2;

    if (nVal != mVal)
    {
        num += (-1)*(2*mVal-1)*(1<<mPosition) + (-1)*(2*nVal-1)*(1<<nPosition);
    }

    return num;
}

最后:

int swapBits3(int num, int nPosition, int mPosition)
{
    int k = ((num >> nPosition) & 1) - (num >> mPosition) & 1;

    return num + k*(1<<mPosition) - k*(1<<nPosition);
}

【讨论】:

    【解决方案3】:

    您可以使用以下宏来避免临时变量或堆栈分配,它适用于任何数字类型:

    #define SWAP_BITS(v,b1,b2) \
        (((v)>>(b1)&1)==((v)>>(b2)&1)?(v):(v^(1ULL<<(b1))^(1ULL<<(b2))))
    

    【讨论】:

    • 当内联函数可以正常工作时,为什么还要使用一个多次评估其参数的宏?
    • 此外,如果 b1b2 将最高有效位转换为 1 转换为这么多的目标类型具有未定义的行为。
    • 是的,我在我的代码中将其更新为1ULL,现在也更新了我的答案。关于多重评估:是的,这可能会发生,但编译器不应该优化它,至少如果它知道没有副作用?如果将函数调用作为表达式传入,宏可能不是最佳选择。但是如果你想将它用于多种类型,你需要多次定义你的函数,不是吗?
    • 编译器无法优化多次评估,宏被逐字替换,编译器必须假定多次评估是有意的。宏对于处理多种类型确实很有用,但新的_Generic 构造允许宏扩展为根据参数类型确定的适当函数调用,例如:#define swap_bits(v,b1,b2) _Generic(+(v), unsigned int: swap_bits_uint, unsigned long: swap_bits_ulong, unsigned long long: swap_bits_ullong)(v, b1, b2)
    【解决方案4】:

    基于 Shay Gold 的解决方案,这里有一些错误修复:

    unsigned int swapBits(unsigned int num, int nPosition, int mPosition) {
        unsigned int k = ((num >> nPosition) & 1) - ((num >> mPosition) & 1);
        return num + k * ((1U << mPosition) - (1U << nPosition));
    }
    

    【讨论】:

    • 不应该反过来吗:int swapBits(int num...unsigned int ...position?另外我不明白为什么移动负数应该是未定义的(尽管您的链接建议这样做),如果我们将位移入符号位或移出符号位,则该数字只会交换符号。它不是特别未定义,但可能出乎意料......
    • @hurikhan77:C 标准明确指出,移动负值具有未定义的行为。在其他语言(例如 java 和 javascript)中,使用 &gt;&gt; 将负值向右移动被定义为执行符号复制,并且一些 C 实现会这样做,但 C 标准并没有强制要求这种行为,也没有你描述的那种行为。
    【解决方案5】:

    Parth Bera 的答案包含一个分支,但异或的想法是正确的。

    假设 p 的位是????A????B???。要将 A 变为 B 并将 B 变为 A,我们需要用 (A^B) 对它们进行异或。为方便起见,让X=A^B

    ????A????B???
    0000X0000X000 ^
    =============
    ????B????A???
    

    我们如何生成0000X0000X000

    ????A????B???    >> (nPostion-mPostion)
    ?????????A???    ^
    ?????????X???    & (1<<mPosition)
    000000000X000    << (nPostion-mPostion)
    0000X00000000    +
    0000X0000X000    ^
    ????A????B???    ==
    ????B????A???
    

    【讨论】:

      猜你喜欢
      • 2022-11-04
      • 1970-01-01
      • 1970-01-01
      • 2011-04-03
      • 2022-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-23
      相关资源
      最近更新 更多