为啥逻辑左移与算术左移相同?

Posted

技术标签:

【中文标题】为啥逻辑左移与算术左移相同?【英文标题】:Why is Logical Shift Left the Same as Arithmetic Shift Left?为什么逻辑左移与算术左移相同? 【发布时间】:2021-09-23 19:39:20 【问题描述】:

我知道那里有类似的问题。但我很好奇的是为什么逻辑左移和算术左移是一样的。

我知道算术左移和逻辑左移在技术上是相同的,因为 msb(最高有效位)在这两种操作中都没有保留,并且 msb 被替换为 0,并且所有位都只是“移位” “ 剩下。但是,为什么我们不能保留 msb 同时将剩余的位左移以进行左算术移位?算术右移保留了 msb 来表示有符号位,那么我们为什么不对算术左移做同样的事情呢?

例如,在Java中:“>>”是逻辑右移,“>>”是算术右移,但“

【问题讨论】:

左移 1 将最高有效位替换为之前的第二个最高有效位 - 它用 0 替换 最低 有效位。当然,会有没有什么能阻止您定义自己的操作,该操作执行左移保留最低有效位,但这并不是一个足够有用的操作,因为它不能成为任何流行语言的原语。 另见:en.wikipedia.org/wiki/… 所以,如果我理解正确,在算术右移中,最高有效位被保留,因为 1 的 msb 将被解释为负号,而 0 将被解释为一个积极的迹象。如果是这种情况,为什么我们不能对算术左移做同样的事情? 当我们执行算术左移时,我们不希望负数也保持负数吗?因为左移相当于除以 2?如果我们只是简单地向左移动,在某些情况下,将 1 的最高位和 0 的第二位移除,我们不是在改变数字的符号吗? 如果你左移一个负数变成一个正数,那么你得到的结果就像你乘以 2 一样;无论哪种方式,它都是整数溢出并且您没有得到“正确”的答案,因为整数的固定宽度不足以代表“正确”的答案。如果您改为保留符号位,那么乘以 2 仍然不会得到“正确”答案,出于同样的原因 - 您只会得到错误的否定结果,而不是错误的肯定结果。 【参考方案1】:

正常的左右算术移位都保留符号位。所以

-32 >> 1 == -16
-16 << 1 == -32

因此,从某种意义上说,算术左移既是算术也是逻辑的,因为算术和非算术位操作都可以完成。

但是需要特别处理一个右逻辑移位来移位符号位并用0位填充左侧。

-1 &gt;&gt;&gt; 1 == 2147483647

如果要完成非算术位操作,这是必不可少的。但是如何进行保留符号的左算术移位?

考虑一个 4 位寄存器,msb 是符号并且它被保留。想象一下&lt;&lt; 运算符的工作方式如下

0111 == 7
0111 << 1 == 0110 == 6
0110 << 1 == 0100 == 4
0100 << 1 == 0000 == 0

Imo,那用处不大。

【讨论】:

【参考方案2】:

但是,为什么我们不能保留 msb,同时将其余位左移以进行左算术移位?

我们可以做到,例如这里是该想法的 java 实现:

int shiftLeftPreserveMSB(int x, int k) 
    return (x & Integer.MIN_VALUE) | ((x << k) & Integer.MAX_VALUE);

但这真的有用吗?例如,它有一个可疑的属性,即每当结果与x &lt;&lt; k 不同时,都不结果匹配(long)x &lt;&lt; k。从算术的角度来看,这似乎不是很有用。也许是这样,但至少这是一个奇怪的操作。这样的操作可能还有其他用途,例如在 bithacks 中,尽管我不知道有任何此类用途。

【讨论】:

以上是关于为啥逻辑左移与算术左移相同?的主要内容,如果未能解决你的问题,请参考以下文章

左移与右移

golang 使用位左移与iota计数配合可优雅地实现存储单位的常量枚举

C语言位运算符:与或异或取反左移与右移详细介绍

汇编--逻辑指令

汇编中的移位指令(8086CPU)

C语言位运算符:与或异或取反左移与右移详细介绍