C# 为什么F#位运算符使用1';签名类型是什么?
我在看按位操作的F#doc: 按位右移运算符。这个 结果是第一个带位的操作数 按中的位数右移 第二个操作数。位移位 最不重要的位置不是 旋转到最重要的位置 位置。对于无符号类型,最 有效位用数字填充 零。对于签名类型,最 有效位用1填充。 第二个参数的类型是 int32 这个设计选择的动机与C++语言(也可能是C语言)相比,MSB是用零填充的?例如:C# 为什么F#位运算符使用1';签名类型是什么?,c#,c++,f#,history,bit-shift,C#,C++,F#,History,Bit Shift,我在看按位操作的F#doc: 按位右移运算符。这个 结果是第一个带位的操作数 按中的位数右移 第二个操作数。位移位 最不重要的位置不是 旋转到最重要的位置 位置。对于无符号类型,最 有效位用数字填充 零。对于签名类型,最 有效位用1填充。 第二个参数的类型是 int32 这个设计选择的动机与C++语言(也可能是C语言)相比,MSB是用零填充的?例如: int mask = -2147483648 >> 1; // C++ code 其中-2147483648= 10000000 0
int mask = -2147483648 >> 1; // C++ code
其中-2147483648=
10000000 00000000 00000000 00000000
掩码等于1073741824
其中1073741824=
01000000 00000000 00000000 00000000
11000000 00000000 00000000 00000000
现在,如果您用F#(或C#)编写相同的代码,这将确实用1填充MSB,您将得到-1073741824
其中-1073741824=
01000000 00000000 00000000 00000000
11000000 00000000 00000000 00000000
回答修改后的问题(在评论中): < > C和C++标准没有定义正确的移位负值的结果(它是实现定义的,或者是未定义的,我记不起是哪个)。
这是因为标准的定义反映了底层指令集的最低公分母。例如,如果指令集不包含
asr
原语,则强制执行真正的算术移位需要几个指令。标准规定了一个或两个补码的表示,这一事实使情况更加复杂。有符号移位具有很好的特性,即将x向右移位n对应于地板(x/2n)
在.NET上,这两种类型的操作都有CIL操作码(
shr
执行有符号移位和shr.un
执行无符号移位)。F#和C#根据被移位类型的符号选择要使用的操作码。这意味着,如果需要其他行为,只需在移位之前和之后执行数字转换(这实际上没有运行时影响,因为数字是如何存储在CLR上的-堆栈上的int32与uint32无法区分)在C和C++中,否定值的转移结果没有在标准中定义。@ OLI:啊,我明白了,这就是原因,顺便说一下,这句话听起来有点怪。当然,它应该说“对于负值,最重要的位是用它填充的”,所以我的问题应该更多:为什么C和C++没有定义正确的符号转换到语言中?@ ScReGig:因为C/C++不需要2的补码整数。很多东西都是官方未定义的行为,因为它们在1的补充硬件上的工作方式不同,这让人非常恼火。C也不需要每个字节8位。在大多数特定的C实现中,右移有符号整数使用算术移位,在符号位的副本中移位。我不知道.NET上的语义是什么,但在典型的C实现中,有一系列病态情况下移位-除法等价性不成立。例如,通常:(-1>>1)!=(-1/2)
@Oli-是的,在.NET中也是如此。。。我将进行编辑以澄清。@Oli,严格来说,-1>>1
和-1/2
都正确地除以零。不过,他们的取整方式有所不同,移位进行统计取整,整数除法进行小学取整。在假设等价的情况下仍然会导致错误,但这仍然是一种移位-除法等价。Jon,我真的怀疑在任何语言中是否有任何操作可以“正确地除以零”…)呵呵。是的,那是一个有趣的打字错误。