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)
带符号的移位具有良好的属性,即右移x对应于floor(x/2 n).
在.NET上,有两种类型的操作的CIL操作码(shr
进行有符号的移位和shr.un
进行无符号移位).F#和C#根据要移位的类型的符号选择要使用的操作码.这意味着如果你想要其他行为,你只需要在移位之前和之后执行数字转换(由于数据存储在CLR上的方式实际上没有运行时影响 - 堆栈上的int32与uint32无法区分) .
要回答改革后的问题(在评论中):
C和C++标准没有定义右移负值的结果(它是实现定义的,或者是未定义的,我不记得哪个).
这是因为标准被定义为反映基础指令集的最低公分母.例如,如果指令集不包含asr
基元,则执行真正的算术移位需要几条指令.这是由事实进一步复杂化的是,标准规定无论是一个人或二进制补码表示.