【问题标题】:Why does the F# Bitwise Operator pad with 1's for signed types?为什么 F# 位运算符用 1 填充有符号类型?
【发布时间】:2010-09-29 21:44:25
【问题描述】:

我正在查看有关按位运算的 F# 文档:

按位右移运算符。这 结果是第一个带有位的操作数 右移的位数 第二个操作数。位移开 最不重要的位置不是 旋转到最重要的 位置。对于无符号类型,最 有效位填充 零。对于有符号类型,最 有效位用 1 填充。 第二个参数的类型是 int32.

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

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

【问题讨论】:

  • 在 C 和 C++ 中,标准中没有定义移位负值的结果。
  • @Oli:啊,我明白了,所以这就是原因
  • 顺便说一句,这句话听起来有点奇怪。当然应该说“对于负值,最重要的位用1填充”?
  • 所以我的问题应该更多:为什么 C 和 C++ 没有定义带符号的右移语言?
  • @Stringer:因为 C/C++ 不需要 2 的补码整数。很多事情都是官方未定义的行为,因为它们在 1 的补码硬件上的工作方式不同,这非常令人讨厌。 C也不需要每字节8位。在大多数特定的 C 实现中,对有符号整数进行右移使用算术移位,即移入符号位的副本。

标签: c# c++ f# history bit-shift


【解决方案1】:

有符号移位具有很好的性质,即将 x 右移 n 对应于 floor(x/2n)。

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

【讨论】:

  • 我不知道 .NET 上的语义是什么,但在典型的 C 实现中,存在移位-除法等价不成立的一系列病态情况。例如,通常:(-1 >> 1) != (-1 / 2).
  • @Oli - 是的,在 .NET 中也是如此......我将进行编辑以澄清。
  • @Oli,严格来说-1 >> 1-1 / 2 都正确除以零。但是,它们的舍入方式不同,移位进行统计舍入,整数除法进行小学舍入。在假定等价的情况下仍然会导致错误,但它仍然是一个移位除法等价。
  • 乔恩,我真的怀疑你用任何语言进行任何操作来“正确除以零”...... :)
  • 嘿。是的,这是一个有趣的错字。
【解决方案2】:

回答改革后的问题(在 cmets 中):

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

这是因为该标准被定义为反映底层指令集的最低公分母。例如,如果指令集不包含asr 原语,则执行真正的算术移位需要多条指令。标准要求 一个的 两个的补码表示这一事实使情况变得更加复杂。

【讨论】:

    猜你喜欢
    • 2015-03-24
    • 1970-01-01
    • 2012-11-12
    • 2011-03-08
    • 1970-01-01
    • 2022-12-06
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多