为什么F#Bitwise运算符用1表示签名类型?

Str*_*ger 3 c# c++ f# history bit-shift

我在按位操作上看F#doc:

按位右移运算符.结果是第一个操作数,其位向右移动第二个操作数中的位数.偏离最不重要位置的位不会旋转到最重要的位置.对于无符号类型,最高有效位用零填充.对于有符号类型,最高有效位用1填充.第二个参数的类型是int32.

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

int mask = -2147483648 >> 1; // C++ code
Run Code Online (Sandbox Code Playgroud)

其中-2147483648 =

10000000 00000000 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

和掩码等于1073741824

1073741824 =

01000000 00000000 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

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

其中-1073741824 =

11000000 00000000 00000000 00000000
Run Code Online (Sandbox Code Playgroud)

kvb*_*kvb 6

带符号的移位具有良好的属性,即右移x对应于floor(x/2 n).

在.NET上,有两种类型的操作的CIL操作码(shr进行有符号的移位和shr.un进行无符号移位).F#和C#根据要移位的类型的符号选择要使用的操作码.这意味着如果你想要其他行为,你只需要在移位之前和之后执行数字转换(由于数据存储在CLR上的方式实际上没有运行时影响 - 堆栈上的int32与uint32无法区分) .

  • 我不知道.NET上的语义是什么,但在典型的C实现中,存在一系列病态情况,其中移位 - 除法等价不成立.例如,通常:`( - 1 >> 1)!=( - 1/2)`. (3认同)

Oli*_*rth 5

要回答改革后的问题(在评论中):

C和C++标准没有定义右移负值的结果(它是实现定义的,或者是未定义的,我不记得哪个).

这是因为标准被定义为反映基础指令集的最低公分母.例如,如果指令集不包含asr基元,则执行真正的算术移位需要几条指令.这是由事实进一步复杂化的是,标准规定无论是一个人二进制补码表示.