c++ 为什么F#位运算符在有符号类型中填充1?

mm9b1k5b  于 2023-01-06  发布在  其他
关注(0)|答案(2)|浏览(112)

我在看F# doc的位操作:

按位右移运算符。结果是将第一个操作数的位右移第二个操作数中的位数。移出最低有效位置的位不会循环到最高有效位置。对于无符号类型,最高有效位用零填充。对于有符号类型,最高有效位用1填充。第二个参数的类型为int 32。

与 C++ (可能也是C语言)中MSB用零填充相比,这种设计选择背后的动机是什么?例如:

int mask = -2147483648 >> 1; // C++ code

其中-2147483648 =

10000000 00000000 00000000 00000000

掩码等于1073741824
其中1073741824 =

01000000 00000000 00000000 00000000

现在,如果你用F#(或C#)编写相同的代码,这确实会用1填充MSB,你会得到-1073741824。
其中-1073741824 =

11000000 00000000 00000000 00000000
nbnkbykc

nbnkbykc1#

带符号移位有一个很好的性质,将x右移n对应于floor(x/2n)。
在.NET上,这两种类型的操作都有CIL操作码(shr执行有符号移位,shr.un执行无符号移位)。F#和C#根据要移位的类型的有符号性来选择要使用的操作码。这意味着如果您想要其他行为,你只需要在移位前后执行一次数值转换(由于数字在CLR上的存储方式-堆栈上的int 32与uint 32无法区分,因此实际上对运行时没有影响)。

ni65a41a

ni65a41a2#

要回答改革后的问题(在评论中):
C和C++标准没有定义将负值右移的结果(要么是实现定义的,要么是未定义的,我记不清是哪一个了)。
这是因为该标准被定义为反映底层指令集的最小公分母。例如,如果指令集不包含asr原语,则强制执行真正的算术移位需要几条指令。由于该标准要求 * 要么 * 一的 * 要么 * 二的补码表示法,这使得情况更加复杂。

相关问题