【问题标题】:Bitwise bit shifting and why this solution works按位位移以及此解决方案为何有效
【发布时间】:2018-01-23 17:05:18
【问题描述】:

我一直在 codefights.com 上进行代码战,我在下面遇到了这个问题。我自己解决了这个问题,但是当我研究其他人的解决方案时,我发现一个比我短得多的解决方案,但我似乎无法理解他们为什么这样做。

问题是:

给你一个最多包含四个非负整数的数组,每个小于 256。 你的任务是按以下方式将这些整数打包成一个数字 M:

数组的第一个元素占据M的前8位; 第二个元素占据接下来的 8 位,依此类推。 返回得到的整数M。

注意:短语“M 的第一位”指的是 M 的最低有效位 - 整数的最右边位。如需进一步说明,请参阅以下示例。

例子

对于 a = [24, 85, 0],输出应该是 arrayPacking(a) = 21784.

数组 [24, 85, 0] 在二进制中看起来像 [00011000, 01010101, 00000000]。 将这些打包成一个数字后,我们得到 00000000 01010101 00011000(为方便起见放置了空格),等于 21784。

他们的回答是:

func arrayPacking(a []int) (sum int) {
    for i := range a {
        sum += a[len(a) - i - 1] << uint((len(a) - i - 1) * 8)
    }
    return
}

此代码如何仅通过使用 0、8、16 等间隔返回正确的移位量?我最近一直在按位进行研究,但我似乎仍然无法解释为什么会这样。

【问题讨论】:

  • 我不确定我是否理解这个问题。您移动 8 的倍数,因为字节是 8 位。你能澄清你在问什么吗?
  • 尽管len(a)-i-1 位有点烦人,这似乎很简单(尽管 n0 16 位,你得到前 8 个零,85 8 位,得到中间的01010101。如果你没有注意到,256 = 1&lt;&lt;8

标签: arrays go bit-manipulation bit shift


【解决方案1】:

首先,用 Go 编写解决方案。我们将 little-endian、base-256 数字转换为 base-2(二进制)数字。左移 8 位乘以 256。

package main

import (
    "fmt"
)

func pack(digits []int) (number int) {
    // digits are little-endian, base-256 (1 << 8 = 256)
    for i, digit := range digits {
        number += digit << uint(i*8)
    }
    return number
}

func main() {
    a := []int{24, 85, 0}
    m := pack(a)
    fmt.Println(m)
}

游乐场:https://play.golang.org/p/oo_n7CiAHwG

输出:

21784

现在你应该可以找出他们丑陋的答案了:

func arrayPacking(a []int) (sum int) {
    for i := range a {
        sum += a[len(a) - i - 1] << uint((len(a) - i - 1) * 8)
    }
    return
}

【讨论】:

    【解决方案2】:

    8 的倍数移位与 256 的倍数相乘相同,例如x &lt;&lt; 0*8 == x * 256⁰x &lt;&lt; 1*8 == x * 256¹x &lt;&lt; 2*8 == x * 256²等,所以代码可以这样重写,使用math.Pow

    func arrayPacking(a []int) (sum int) {
      for i := range a {
        sum += a[len(a) - i - 1] * int(math.Pow(256, (len(a) - i - 1)))
      }
      return
    }
    

    或者你的问题是为什么这种包装有效?

    【讨论】:

    • 你忘记了类型转换。
    • 谢谢。你能帮我加一下吗?我不会写Go,细节忘记了。
    • 我也想将您的答案标记为解决方案。我选择了以下答案,因为它被分解得更多并且用 go 编写(我觉得这可以帮助未来有同样问题的读者)。感谢您的回复。
    猜你喜欢
    • 1970-01-01
    • 2021-05-06
    • 2015-09-12
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多