英文:
When I do bitwise flip operation in C on integer 1, I get -2 and not 4294967294, how can I get 4294967294?
问题
这是一个新手级别的HackerRank问题,要求翻转由32位表示的长整数的位,并返回结果。
例如:
1 被表示为:00000000 00000000 00000000 00000001
~ 运算符翻转位。
所以 ~1 = 11111111 11111111 11111111 11111110
当我在长整数上执行 ~1 时,它返回的是 -2,而不是 4294967294,尽管它们在32位二进制形式中表示相同。
我实现了以下代码:
long flippingBits(long n) {
    unsigned long m = n;
    unsigned long x = ~n;
    return x;
}
我得到了 -2 作为结果。我尝试了只使用 "long",但得到了相同的结果。我还尝试了使用强制类型转换 unsigned long x = (unsigned long)~n;,但结果仍然相同。
所以后来我只是使用了异或操作,它起作用了:
long flippingBits(long n) {
    unsigned long m = n;
    unsigned long x = n ^ 4294967295;
    return x;
}
为什么在C中 ~ 操作符对于 1 不会表示为 4294967294 而是 -2 呢?如果可能的话,我需要做什么来让 ~ 运算符返回 4294967294 而不是 -2?
英文:
It's one of the newbie HackerRank problems, where it asks to flip bits of a long represented by 32 bits, and return the value.
e.g.:
1 is represented as: 00000000 00000000 00000000 00000001
~ operator flips its bits.
so ~1 = 11111111 11111111 11111111 11111110
When I do ~1 on a long, it returns -2, not 4294967294 despite both are represented equally in 32 bit binary form.
I implemented the code below:
long flippingBits(long n) {
    unsigned long m = n;
    unsigned long x = ~n;
    return x;
}
I got -2 as result. I tried with just "long", but got same result. I tried casting too with unsigned long x = (unsigned long)~n; but got same results again.
So then I just used XOR operation and it worked:
long flippingBits(long n) {
    unsigned long m = n;
    unsigned long x = n ^ 4294967295;
    return x;
}
Why ~ operation of 1 not represented as 4294967294 but -2 in C? What do I need to do to make ~ operator return 4294967294 and not -2 (if it's possible)?
答案1
得分: 1
在一些平台上,sizeof long == sizeof int。
标准定义了long int对象的最大值为LONG_MAX,其中LONG_MAX必须至少为2,147,483,647。
因此,4,294,967,294不能由long表示。
修复:
- 始终对
unsigned类型执行位操作。 - 将函数的返回类型从
long更改为unsigned。 - 使用
stdint.h头文件中定义的int32_t和int64_t等类型,这些类型分别保证具有32位和64位。 
英文:
On some platforms, sizeof long == sizeof int.
The standard defines the maximum value for an object of a long int to be LONG_MAX, where LONG_MAX must be at least 2,147,483,647.
Thus, 4,294,967,294 can't be represented by a long.
Fix:
- Always do bitwise operations on 
unsignedtypes. - Change the return type of the function from 
longtounsigned. - Use types like 
int32_tandint64_tdefined instdint.hheader file, which are guaranteed to have32and64bits respectively. 
答案2
得分: 1
~ 应用于一个类型为有符号 long 的操作数 n。假设长整型为32位,那么它的二进制表示将变为 11111111 11111111 11111111 11111110。但在十进制表示中,这意味着 -2,因为绝大多数实际计算机使用的是 二进制补码。
当转换为 unsigned long 时,它确实变为 4294967294,因为这是有符号到无符号的转换方式。
> 我得到了 -2 作为结果。
返回时,你再次将其转换为有符号数。这种转换是与实现相关的,但在所有主流系统上,你很可能会再次得到 -2。类似地,如果你尝试使用 printf(""%ld"", my_unsigned_long) 打印一个 unsigned long,那么它很可能会显示存储在 unsigned long 中的带符号十进制表示。
> 所以我只是使用了异或操作,它起作用了
在32位系统的情况下,n ^ 4294967295 的操作数之一,即常数 4294967295,是类型为 long long 的,因为它不能适应任何较小的类型。当编译器尝试确定要用于 4294967295 的类型时,它会自问:它能适应一个 int 吗?不能。它能适应一个 long 吗?不能。它能适应一个 long long 吗?能。
因此,1 ^ 4294967295 得到了预期的 4294967294,因为计算是在类型 long long 上进行的,没有任何影响到符号位。
英文:
~ is applied on an operand n which is of type signed long. Assuming 32 bit long then binary it will become 11111111 11111111 11111111 11111110 indeed. But in decimal representation that means -2 since the vast majority of real-world computers use two's complement.
When converted to unsigned long it does become 4294967294 however, because that's how signed to unsigned conversion works.
> I got -2 as result.
Upon return you convert back to signed again. This conversion is implementation-defined but likely you'll end up with -2 again on all mainstream system. Similarly, if you would attempt to print an unsigned long using printf("%ld", my_unsigned_long) then it will likely display the signed decimal representation of what's stored inside the unsigned long.
> So then I just used XOR operation and it worked
In case of a 32 bit system, then one operand of n ^ 4294967295, namely the 4294967295 constant, is of type long long - because it can't fit in any smaller type. When the compiler tries to determine what type it will use for 4294967295, it will ask itself: Does it fit inside an int? No. Does it fit inside a long? No. Does it fit inside a long long? Yes.
Therefore 1 ^ 4294967295 gives 4294967294 as expected, since the calculation is carried out on type long long and nothing affects the sign bit.
答案3
得分: 0
在使用位运算符之前,您必须考虑以下几个方面:
- 一些填充位的组合可能会生成陷阱表示。N1256脚注
 - 二进制补码不是唯一编码整数的方式。N1256 6.2.6.2
 
为了满足上述要求,我们使用uintN_t而不是long。intN_t没有填充位,而uintN_t是二进制补码表示法。这里的N表示宽度。例如,int8_t表示具有精确宽度为8位的有符号整数类型。唯一的问题是uintN_t是可选的。N1256 7.18.1.1
> 为什么C中的1的~操作不表示为4294967294而表示为-2?如果可能的话,我需要做什么才能使~运算符返回4294967294而不是-2?
4294967294等于UINT32_MAX - 1。因此,我们选择了uint32_t。
uint32_t flippingBits(uint32_t n)
{
    return ~n;
}
英文:
Before using bitwise operators, you must consider several things :
- Some combinations of padding bits might generate trap representations. N1256 footnote
 - Two's complement is not the only way to encode a integer. N1256 6.2.6.2
 
To satisfy above requirments, we use uintN_t  instead of long. intN_t doesn't have padding bits. And uintN_t is two's complement representation. N stands for width. For example, int8_t denotes a signed integer type with a width of exactly 8 bits. The only problem is uintN_t is optional. N1256 7.18.1.1
> Why ~ operation of 1 not represented as 4294967294 but -2 in C? What do I need to do to make ~ operator return 4294967294 and not -2 (if it's possible)?
4294967294 is equal to UINT32_MAX - 1. So we choose uint32_t.
uint32_t flippingBits(uint32_t n)
{
    return ~n;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论