我很难理解这段代码的工作方式和原因。我在这个任务中的合作伙伴完成了这一部分,我无法得到他,以了解它的工作原理和原因。我已经尝试了一些不同的东西来理解它,但任何帮助将非常感激。此代码使用2的补码和32位表示。
/*
* fitsBits - return 1 if x can be represented as an
* n-bit, two's complement integer.
* 1 <= n <= 32
* Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int fitsBits(int x, int n) {
int r, c;
c = 33 + ~n;
r = !(((x << c)>>c)^x);
return r;
}
答案 0 :(得分:15)
c = 33 + ~n;
计算使用n
低位后的剩余高位数。
((x << c)>>c
这将使用与x
的符号位相同的值填充高位。
!(blah ^ x)
这相当于
blah == x
答案 1 :(得分:12)
在2&#39s补充平台上-n
相当于~n + 1
。因此,此平台上的c = 33 + ~n
实际上等同于c = 32 - n
。此c
旨在表示如果int
低位被占用,则32位n
值中有多少高位保留。
请注意此代码中存在两个平台依赖项:2&#39; s-complement平台,32位int
类型。
然后((x << c) >> c
旨在签署那些c
更高阶位。符号填充意味着x
在位位置0
中具有n - 1
的值,这些高阶位必须被清零。但对于x
在位位置1
中n - 1
的值,这些高位位必须用1
填充。这对于使代码适用于x
的负值非常重要。
这引入了另外两个平台依赖:<<
运算符,当移位负值时或在1
移位到符号位(正式地,它是未定义的行为)时>>
表现良好; x
在移动负值时执行符号扩展的运算符(正式地,它是实现定义的)
如上所述,其余部分仅与!(a ^ b)
的原始值进行比较:a == b
相当于x
。如果上述转换没有破坏x
的原始值,那么n
确实适合2 {s}补码表示的{{1}}低位。
答案 2 :(得分:3)
Using the bitwise complement (unary ~
) operator on a signed integer has implementation-defined and undefined aspects。换句话说,即使您只考虑两个补码实现,此代码也不可移植。
重要的是要注意,即使C中的两个补码表示也可能有陷阱表示。 6.2.6.2p2 even states this非常清楚:
如果符号位为1,则应以下列方式之一修改该值:
- 符号位0的相应值被否定(符号和幅度);
- 符号位的值为 - (2 M)(二进制补码);
- 符号位的值为 - (2 M - 1)(补码)。
其中哪一个适用于实现定义,是符号位1和所有值位零(前两个)的值,还是符号位和所有值位1(对于“补充”,是陷阱表示或正常值。
重点是我的。 Using trap representations is undefined behaviour
在默认模式下,有一些实际的实现将该值保留为陷阱表示。我倾向于引用的值得注意的是Unisys Clearpath Dordado on OS2200 (go to 2-29)。请注意该文件的日期;这样的实现不一定是古老的(因此我引用这个实现)。
根据6.2.6.2p4,左移的负值也是未定义的行为。我还没有对现实中的行为做过大量的研究,但我会合理地期望可能存在签名扩展的实现,以及没有实现的实现。这也是形成上述陷阱表示的一种方式,其本质上是未定义的并且因此是不期望的。理论上(或者可能是遥远或不远的未来),您可能还会遇到“对应于计算异常”的信号(这是与SIGSEGV
属于的类似的C标准类别,对应于诸如“除以零”之类的事情或其他不稳定和/或不良行为......
总之,问题中代码的唯一原因是巧合的是,您的实施所做的决定恰好以正确的方式对齐。如果您使用我列出的实现,您可能会发现此代码对某些值的预期效果不正常。
这样的沉重的魔法(正如评论中所描述的那样)并不是真的有必要,而且对我来说并不是那么理想。如果你想要一些不依赖于 magic (例如可移植的东西)来解决这个问题,可以考虑使用它(实际上,这段代码至少可以用1 <= n <= 64
):
#include <stdint.h>
int fits_bits(intmax_t x, unsigned int n) {
uintmax_t min = 1ULL << (n - 1),
max = min - 1;
return (x < 0) * min + x <= max;
}