使用按位运算符确定 Int 是否适合 C 中的 Short
Determining if an Int Fits into a Short in C using Bitwise Operators
我的任务是制作一个函数,return判断 int x 是否适合 C 中的 short(return 如果适合则为 1,否则为 0)。这通常是一个相当简单的解决方案,但我只能使用以下按位运算符:! ~ & ^ | + << >>.
这里还有一些规则:
我最多只能使用其中的 8 个运算符。
不包含任何外部库。
我不允许使用任何条件语句(所以没有 ifs、whiles、
等)。
我唯一可以使用的变量是 int 类型的变量,但我不能
定义像 0x0000ffff 这样的常量。但是,我可以使用 0x0 和 0xff。
假设 int 是 32 位而 short 是 16 位是安全的。
我了解这些算子的基本功能,但对实现逻辑感到困惑。有什么想法吗?
假设2的补码,算术右移,舍弃溢出位的左移,32位int
,则:
x<<16>>16 ^ x
当且仅当 x
适合 16 位 short
. 时, 为零
由于我们被要求 return 零表示不适合,一表示适合,我们可以 return:
! (x<<16>>16 ^ x)
证明:
如果x
适合short
,那么x
•216适合int
,所以x<<16
产生没有溢出的结果,并且 x<<16>>16
恢复 x
(因为只删除零的算术右移实际上是一个没有余数的除法),之后 x ^ x
为零。
如果 x
超过了一个短路,那么 x<<16
就会溢出(我们假设这会导致丢弃高位)。此外,它的值是 y<<16
为某些 y
生成的值之一,这是一个空头。那么 x<<16>>16
必须产生与 y<<16>>16
相同的值,即 y
,与 x
不同,因此 x<<16>>16 ^ x
不能为零。
假设有 2 个补码,您最初的想法是测试所有前导位但 15 位全为 0 或全为 1 确实可行。
11111111 11111111 1xxxxxxx xxxxxxxx /* for negative 16 bits int */
00000000 00000000 0xxxxxxx xxxxxxxx /* for positive 16 bits int */
假设算术右移,你可以右移15来消除未知位,然后只剩下1或0(如果它适合15位)
因此 x>>15
应该是 0 或 -1。
如果为 0,则 !(x>>15) 为真。
如果是-1,则!(~(x>>15))为真。
因此,您可以测试 !(x>>15) | !(~(x>>15))
或者你也可以这样写:!(x>>15) | !(~x>>15)
请注意,上面的表达式不假定 32 位 x,并且还可以用于测试 int64 是否适合 int16...
还有很多其他方法...
由于您也可以使用 +,因此 (x>>15)+1
为 0 或 1。
然后你可以清除最后一位:((x>>15)+1)>>1
.
如果上面的表达式全为 0(假),x
确实适合 16 位 int,因此您需要:
! (((x>>15)+1)>>1)
由你来寻找更多的表达...
我的任务是制作一个函数,return判断 int x 是否适合 C 中的 short(return 如果适合则为 1,否则为 0)。这通常是一个相当简单的解决方案,但我只能使用以下按位运算符:! ~ & ^ | + << >>.
这里还有一些规则:
我最多只能使用其中的 8 个运算符。
不包含任何外部库。
我不允许使用任何条件语句(所以没有 ifs、whiles、 等)。
我唯一可以使用的变量是 int 类型的变量,但我不能 定义像 0x0000ffff 这样的常量。但是,我可以使用 0x0 和 0xff。
假设 int 是 32 位而 short 是 16 位是安全的。
我了解这些算子的基本功能,但对实现逻辑感到困惑。有什么想法吗?
假设2的补码,算术右移,舍弃溢出位的左移,32位int
,则:
x<<16>>16 ^ x
当且仅当 x
适合 16 位 short
. 时,为零
由于我们被要求 return 零表示不适合,一表示适合,我们可以 return:
! (x<<16>>16 ^ x)
证明:
如果x
适合short
,那么x
•216适合int
,所以x<<16
产生没有溢出的结果,并且 x<<16>>16
恢复 x
(因为只删除零的算术右移实际上是一个没有余数的除法),之后 x ^ x
为零。
如果 x
超过了一个短路,那么 x<<16
就会溢出(我们假设这会导致丢弃高位)。此外,它的值是 y<<16
为某些 y
生成的值之一,这是一个空头。那么 x<<16>>16
必须产生与 y<<16>>16
相同的值,即 y
,与 x
不同,因此 x<<16>>16 ^ x
不能为零。
假设有 2 个补码,您最初的想法是测试所有前导位但 15 位全为 0 或全为 1 确实可行。
11111111 11111111 1xxxxxxx xxxxxxxx /* for negative 16 bits int */
00000000 00000000 0xxxxxxx xxxxxxxx /* for positive 16 bits int */
假设算术右移,你可以右移15来消除未知位,然后只剩下1或0(如果它适合15位)
因此 x>>15
应该是 0 或 -1。
如果为 0,则 !(x>>15) 为真。
如果是-1,则!(~(x>>15))为真。
因此,您可以测试 !(x>>15) | !(~(x>>15))
或者你也可以这样写:!(x>>15) | !(~x>>15)
请注意,上面的表达式不假定 32 位 x,并且还可以用于测试 int64 是否适合 int16...
还有很多其他方法...
由于您也可以使用 +,因此 (x>>15)+1
为 0 或 1。
然后你可以清除最后一位:((x>>15)+1)>>1
.
如果上面的表达式全为 0(假),x
确实适合 16 位 int,因此您需要:
! (((x>>15)+1)>>1)
由你来寻找更多的表达...