【问题标题】:Arithmetic right shift examples in my textbook shift in ones when the MSB was zero当 MSB 为零时,我教科书中的算术右移示例移入一个
【发布时间】:2018-08-10 09:06:38
【问题描述】:

我目前正在研究汇编,以及它们之间的位运算的工作原理。特别是算术右移困扰着我。

现在,我正在阅读的书中有几个练习题,其中,我需要对包含以下内容的字节执行此操作:

0100 0100

现在,当算术右移填充最高有效位的值时,在我看来这应该是正确的:

00001000

但是,书上说应该是

11101000

也就是说,从左边开始填充 1 而不是 0。但是最重​​要的位不是0吗?

嗯,还有一个:

0110 0100 >> 3 = 0000 1100

但是,显然这也是错误的,应该是:

11101100

再次,我不明白最重要的位值显然是 0,最左边的那个,但解决方案告诉我应该填写 1?


所以我在这里有一个显然是正确的最后一个:

0111 0010 >> 3 = 0000 1110

这是我所期望的。那么为什么其他这些不正确呢?

如果不理解这一点,阅读汇编非常困难,因为大量乘法和除法被编译为移位运算。

【问题讨论】:

  • 哪本书? (书中确实会发生错误,这看起来像是一个错误,除非有更多的上下文来解释这种奇怪现象)。这应该是 2 的补码还是其他东西(比如一个补码)?但这并不重要; 0100 0100 在 1 的补码中也是正数。是的,它应该移入零以产生与初始值具有相同符号的结果。
  • 这本书(我觉得这本书很好)是:计算机系统一个程序员的观点,作者 Randal E. Bryant 和 David R. O'Hallaron 练习题是第 94 页的 2.16,给出了解决方案在第 184 页

标签: assembly bitwise-operators bit-shift


【解决方案1】:

左移是基础功率增加,右移是减少。因此以 2 为底(二进制)右移是减少 2 的幂,左移是增加。所以右边是除以 2,左边是乘以 2。

问题在于右移和负数,这意味着假设二进制补码,并且还理解处理器不知道或不关心,位就是位,它们对程序员意味着什么。

负的二进制补码表示 msbit 已按照您的理解设置。

因此,如果我想将 -2 0b11111110 除以 2 得到 -1 0b11111111,最好将其右移,但逻辑右移通常意味着用零填充顶部,因此 0b11111110 逻辑右移变为 0b01111111,即不是-1,而是127。某些处理器具有算术右移功能,它不是移入零,而是复制最高位,因此0b11111110 ASR变为0b11111111。 这是使用移位来划分 -2 / 2 的正确/理想答案。

同样理解 0b11111110 同时也代表值 254 和 254/2 = 127。所以算术右移得到 255,这是错误的答案。到目前为止,我们想要为未签名的 LSR 做一个 ASR。

你是对的,你的书可能是错的,或者你只是给我们书的片段。

0b01000100 ASR is 0b00100010
0b01000100 LSR is 0b00100010
0b10001000 ASR is 0b11000100
0b10001000 LSR 0s 0b01000100

多位算术移位只是将它们视为多个单个位,或者只是用原始数字的 msbit 填充顶部

0b10001000 ASR 3 = 0bBBB10001 其中 B 是 1 所以 0b11110001 对于 LSR,BBB 为零 0b00010001

请注意,算术左移和逻辑左移是相同的操作,它们只是从右开始填充零。

【讨论】:

    【解决方案2】:

    当输入的 MSB 为 0 时,任何移位都不会用 1 填充。 请注意,反过来不正确(逻辑右移总是用零填充)。

    如果这本书没有一些额外的上下文,那么它只是一个错误。那不是旋转或其他任何东西。甚至 1 的补码或符号/大小都无法解释它(因为数字在所有 3 种表示中都是正数)。

    在符号位副本中的 2 补码移位中的算术右移。 (例如sar eax, 31 将符号位广播到 32 位寄存器的所有位。

    算术移位结果的符号将始终与输入的符号相同。


    逻辑右移总是移入零。


    逻辑和算术的左移是相同的:它们移入零。 (x86 有一个sal mnemonic,但它只是与 shl 相同的操作码的替代名称。后来的 x86 扩展不再提及算术左移,例如有一个 SIMD pslld(压缩整数左移逻辑)但是没有pslad。)

    在符号/幅度中,我猜算术左移不会影响符号位。我不确定 1 的补码算术左移是否需要任何特殊处理。

    但是 2 的补码算术左移与逻辑相同。 (与add same,same 相同,左移 1 也就是乘以 2。)

    【讨论】:

    • JFYI:Z80 具有未记录的(非官方)“sll”或“sl1”操作码,它确实向左移动并将 LSB 设置为 1。但我不记得看到过类似的“正确”转变。
    【解决方案3】:

    说到C,这在书上是一个错误,根据standard

    • 对无符号类型进行移位按预期工作(要移位的位数必须小于要移位的数字的宽度且非负数)。
    • 有符号类型的转换是不同的。如果要移动的数字为负数,则左移未定义,但右移由实现定义。

    因此,无符号数的移位是明确定义的,但对于有符号数则不是(更好的是,没有通用的定义)。

    为了完整起见,标准说:

    E1 >> E2 的结果是 E1 右移 E2 位位置。如果 E1 具有无符号类型或 E1 具有带符号类型和非负值,则结果的值是 E1 / 2E2 的商的整数部分。如果 E1 有带符号类型和负值,则结果值是实现定义的 ()。

    所以考虑到 OP 的例子(正数),没有理由用一个来填充。

    谈算术移位(我们以x86 为例):

    在算术移位(也称为有符号移位)中,就像逻辑移位一样,从末尾滑出的位会消失(除了最后一个,它进入进位标志)。但是在算术移位中,空格的填充方式是保留被滑动数字的符号。因此,算术移位更适合二进制补码格式的有符号数。

    SAR 指令在数字为负数时会填充一个(为了保持符号),例如:

    sar 10110011b, 2 #the result is 11101100b

    (shr 10110011b, 2 #the result is 00101100b)

    但同样,OP 的例子是在谈论正数,所以没有理由用一个来填充。

    总而言之,当应用右移时,可以用 one 填充,但在那些情况下则不行。

    【讨论】:

      猜你喜欢
      • 2020-04-26
      • 2017-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 2010-11-05
      相关资源
      最近更新 更多