如何按位获取数字而不是求反符号位

How to get the bitwise not of a number but do not negate the sign bits?

本文关键字:符号 何按位 获取 数字      更新时间:2023-10-16

我有一个代表掩码的数字,我想得到负掩码(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

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

size_t nMsk = (~msk) & 0xF;

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

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

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

如果你假设你正在使用的最大位数,你可以得到一个"所有位等于或低于最高设定位"的掩码,而不需要太多的魔术(尽管魔术可能更快)

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

然后只需 XOR 与它:

nMsk = msk ^ m;

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

符号

位只是颠倒的,因为~不考虑有符号/无符号。例:

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 */

如果只想反转某些位,则可以改用 xor,例如:

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

这是我的尝试(见输出):

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

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

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

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