为什么 F# 按位运算符对于有符号类型用 1 填充?

发布于 2024-09-25 15:11:05 字数 702 浏览 5 评论 0原文

我正在查看有关按位运算的 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

I was looking at F# doc on bitwise ops:

Bitwise right-shift operator. The
result is the first operand with bits
shifted right by the number of bits in
the second operand. Bits shifted off
the least significant position are not
rotated into the most significant
position. For unsigned types, the most
significant bits are padded with
zeros. For signed types, the most
significant bits are padded with ones.
The type of the second argument is
int32.

What was the motivation behind this design choice comparing to C++ language (and probably C too) where MSB are padded with zeros? E.g:

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

where -2147483648 =

10000000 00000000 00000000 00000000

and mask is equal to 1073741824

where 1073741824 =

01000000 00000000 00000000 00000000

Now if you write same code in F# (or C#), this will indeed pad MSB with ones and you'll get -1073741824.

where -1073741824 =

11000000 00000000 00000000 00000000

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三生一梦 2024-10-02 15:11:05

有符号移位有一个很好的特性,即 x 右移 n 对应于 Floor(x/2n)。

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

The signed shift has the nice property that shifting x right by n corresponds to floor(x/2n).

On .NET, there are CIL opcodes for both types of operations (shr to do a signed shift and shr.un to do an unsigned shift). F# and C# choose which opcode to use based on the signedness of the type which is being shifted. This means that if you want the other behavior, you just need to perform a numeric conversion before and after shifting (which actually has no runtime impact due to how numbers are stored on the CLR - an int32 on the stack is indistinguishable from a uint32).

故事灯 2024-10-02 15:11:05

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

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

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

To answer the reformed question (in the comments):

The C and C++ standards do not define the result of right-shifting a negative value (it's either implementation-defined, or undefined, I can't remember which).

This is because the standard was defined to reflect the lowest common denominator in terms of underlying instruction set. Enforcing a true arithmetic shift, for instance, takes several instructions if the instruction set doesn't contain an asr primitive. This is further complicated by the fact that the standard mandates either one's or two's complement representation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文