Golang:两个补码和fmt.Printf

时间:2016-06-02 04:12:54

标签: go

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

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

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

输出-101。不是我所期待的。格式是不同还是不使用Two的补码?

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

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

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

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

有人可以澄清这个吗?

3 个答案:

答案 0 :(得分:8)

我认为答案在于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.fmtInt64pp.printArg在同一个函数中从top-a调用。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

这是一个不使用 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