【问题标题】:How to get the bitwise not of a number but do not negate the sign bits? [closed]如何按位而不是数字但不否定符号位? [关闭]
【发布时间】:2016-05-30 20:43:08
【问题描述】:

我有一个代表掩码的数字,我想得到负掩码(0110,即 6)。我想不按位做,但似乎它也否定了符号位,我得到了一个不需要的值......

size_t msk = 9; // that is 1001, or 000...01001 on more bits
size_t nMsk = ~msk; // this I want to be 6, that is 0110, but bitwise not  
                    // is negating all the bits, so I get 111...10110

有没有快速的方法(没有循环)?

编辑 更多信息:

我在其中一个答案的评论中添加了一些更好的案例: 在我的例子中,16 是 100000000,~16 不是 111011111111,而是 000011111111

【问题讨论】:

  • 这是干什么用的?你确定这是问题吗?通常当人们想要这样的东西时,事实证明他们被额外的设置位分散了注意力,结果证明他们不是问题。如果您使用 4 位数字,那很简单:nMsk = msk ^ 15
  • 不,我正在处理更大的数字,但在 4 位上显示它很容易 :) 抱歉
  • 唯一的方法是对设置为 1 的值进行异或运算,直到 the highest bit in your input。
  • size_t 未签名!因此,根据定义,它没有符号位。你的问题不清楚。
  • @sop:不,不是。这可能是一个 XY 问题。您提出的“解决方案”背后的实际问题是什么?

标签: c++ c


【解决方案1】:

如果您希望您的值按照您的要求为 6,那么您需要删除它前面的所有未使用的位。

size_t nMsk = (~msk) & 0xF;

用0xF 屏蔽它,它等于二进制中的1111 将删除除最后4 位之外的所有位,从而产生您想要的值。

【讨论】:

  • 这个答案很不错,但是如果我不知道掩码使用的位数,我该怎么办?
  • @sop 在这一点上,我认为您需要告诉我们您为什么要这样做,因为一开始这样做似乎很奇怪。
【解决方案2】:

OP 在一条评论中说他事先不知道位数。解决此问题的一种方法是使用查找表。一个 8 位的例子是

uint8_t lookup[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
result ^= lookup [numberofbits];

【讨论】:

  • 除了OP还需要查找数字中的位数,这可能需要循环。
【解决方案3】:

如果您对正在使用的最大位数做出假设,则无需太多魔法即可获得“所有位等于或低于最高设置位”的掩码(尽管魔法可能更快)

size_t m = msk;
m |= m >> 1;
m |= m >> 2;
m |= m >> 4;
m |= m >> 8;
m |= m >> 16;
m |= m >> 32; // if size_t is more than 32 bits

然后与它进行异或:

nMsk = msk ^ m;

虽然这是一个不寻常的操作,但我仍然怀疑你的意思是别的。

【讨论】:

  • 确实不是循环,而是展开循环。
  • 是的,最后我使用了循环,但我认为可能有更简单的方法可以做到这一点,我认为循环是可以的
【解决方案4】:

符号位只是反转,因为 ~ 不考虑有符号/无符号。示例:

uint8_t a = 54; /*     0011 0110 */
uint8_t b = ~a; /* 201 1100 1001 */

int8_t c = 54; /*      0011 0110 */
int8_t d = ~c; /* -55  1100 1001 */

如果只想反转部分位,可以使用异或代替,例如:

uint8_t a = 54;     /*     0011 0110 */
uint8_t b = a ^ 15; /* 57  0011 1001 */

【讨论】:

  • 我也测试了这个想法,但似乎我应该知道掩码使用的位数,但我不确定这是固定的......这就是为什么我要求的东西知道从我的号码中删除 1s
  • 您的用例到底是什么?
  • 我的情况是 0x1b7,我期望的是 0x48,但我希望它也适用于 0x10(即返回 0xF)
【解决方案5】:

这是我的尝试 (see the output):

#include <climits>
#include <cmath>
#include <bitset>
#include <iostream>

template <typename T>
T build_mask(T num) {
    const int up_to_bit = ceil(log2(num));
    for (int i = 0; i < up_to_bit; i++)
        num |= 1 << i;
    return num;
}

template <typename T>
std::bitset<sizeof(T) * CHAR_BIT> get_bits(T num) {
    return std::bitset<sizeof(T) * CHAR_BIT>(num);
}

int main() {
    int32_t msk = 9;
    int32_t nMsk = ~msk & build_mask(msk);

    std::cout << "value: " << msk << std::endl;
    std::cout << "bits : " << get_bits(msk) << std::endl;
    std::cout << "mask : " << get_bits(build_mask(msk)) << std::endl;

    std::cout << "value: " << nMsk << std::endl;
    std::cout << "bits : " << get_bits(nMsk) << std::endl;

    return 0;
}

【讨论】:

    【解决方案6】:

    如何通过按位异或保留符号位:

    size_t nMsk = ~msk ^ (1 << ((sizeof(size_t) * CHAR_BIT) - 1));
    

    它将首先反转掩码,然后切换符号位。

    【讨论】:

    • 这就是线索,它被转移到符号位的位置
    • 对于 4 字节的 size_t,移位将是 1 &lt;&lt; (4-2),而不是预期的 1 &lt;&lt; (32 - 1)。 (假设系统有8位字节)
    • 对不起,你完全正确,我想我在回答你的时候还没有完全清醒;)
    • 好的,“符号位”是指 x 位掩码前面的 1(例如,16 是 100000000,~16 不是 111000000000,在我的情况下是 000011111111)
    猜你喜欢
    • 2015-01-07
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多