【问题标题】:Two's complement and fmt.Printf二进制补码和 fmt.Printf
【发布时间】:2016-10-01 15:23:33
【问题描述】:

因此计算机使用二进制补码在内部表示有符号整数。即,-5 表示为 ^5 + 1 = "1111 1011"。

但是,尝试打印二进制表示,例如以下代码:

var i int8 = -5
fmt.Printf("%b", i)

输出-101。不完全是我所期望的。是格式不同还是根本不使用二进制补码?

有趣的是,转换为 unsigned int 会产生“正确”的位模式:

var u uint8 = uint(i)
fmt.Printf("%b", u)

输出是 11111011 - 正好是 -5 的 2s 补码。

所以在我看来,这个值实际上是在内部使用二进制补码,但格式是打印无符号 5 并在前面加上 -

有人可以澄清一下吗?

【问题讨论】:

  • 我不知道为什么有人认为这很“奇怪”。无论您使用什么基数,负数仍然是负数。如果您要求以 8、12 或 16 为基数,我希望得到同样的结果。
  • 好吧,我没说奇怪。我只是想了解 2s 的补码,结果出乎我的意料。
  • 我不认为你真的希望通过玩用高级语言编写的数字格式化函数来理解 2 的补码。
  • 你有什么建议?

标签: go


【解决方案1】:

我相信答案在于fmt 模块如何格式化二进制数,而不是内部格式。

如果您查看fmt.integer,该函数首先执行的操作之一是将负符号整数转换为正整数:

   165      negative := signedness == signed && a < 0
   166      if negative {
   167          a = -a
   168      }

然后有逻辑将- 附加到输出here 的字符串前面。

IOW -101 真的是 - 附加到 5 二进制。

注意:fmt.integer 是从print.go 中的pp.fmtInt64 调用的,它本身是从同一函数中的pp.printArg 调用的。

【讨论】:

    【解决方案2】:

    这里是不使用unsafe的方法:

    package main
    
    import (
       "fmt"
       "math/bits"
    )
    
    func unsigned8(x uint8) []byte {
       b := make([]byte, 8)
       for i := range b {
          if bits.LeadingZeros8(x) == 0 {
             b[i] = 1
          }
          x = bits.RotateLeft8(x, 1)
       }
       return b
    }
    
    func signed8(x int8) []byte {
       return unsigned8(uint8(x))
    }
    
    func main() {
       b := signed8(-5)
       fmt.Println(b) // [1 1 1 1 1 0 1 1]
    }
    

    在这种情况下,您也可以使用[8]byte,但如果您有上述内容会更好 一个正整数,并且想要修剪前导零。

    https://golang.org/pkg/math/bits#RotateLeft

    【讨论】:

      【解决方案3】:

      必须使用不安全的指针才能正确表示二进制格式的负数。

      package main
      
      import (
          "fmt"
          "strconv"
          "unsafe"
      )
      
      func bInt8(n int8) string {
          return strconv.FormatUint(uint64(*(*uint8)(unsafe.Pointer(&n))), 2)
      }
      
      func main() {
          fmt.Println(bInt8(-5))
      }
      

      输出

      11111011
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-23
        • 1970-01-01
        • 1970-01-01
        • 2021-12-22
        • 2015-04-12
        • 1970-01-01
        • 1970-01-01
        • 2014-09-20
        相关资源
        最近更新 更多