对于int8 var,如何理解“-128 / -1”和“-128 * -1”的结果是-128?

pyn*_*exj -1 go

几周前刚开始学习 Go,这种行为让我很困惑。

var n int8 = -128

n /= -1
fmt.Println(n)

n *= -1
fmt.Println(n)
Run Code Online (Sandbox Code Playgroud)

上面的代码都会输出-128. 我也试过-64 * -2这也导致-128.

值是否-128特殊,这意味着这里的int溢出

Mar*_*arc 5

它不是用于溢出的特殊值,它只是一个有符号的 8 位整数的最小值(有效范围是[-128, 128),意味着 -128 包括在内,但 128 不是)。

在简单的情况下,例如增加最大值(例如:)int8(127) + 1,您会溢出整数并以最小值结束。

在 Go 中,这是完全可以接受的,正如规范中提到的

对于有符号整数,运算 +、-、*、/ 和 << 可能合法溢出,结果值存在并且由有符号整数表示、运算及其操作数确定性地定义。溢出不会导致运行时恐慌。在不发生溢出的假设下,编译器可能不会优化代码。例如,它可能不会假设 x < x + 1 总是正确的。

但是您的具体情况有所不同,这是因为采用最负值的二进制补码返回相同的 value

最简单的例子是这个:

    var n int8 = -128
    fmt.Println(-n)
    // output -128
Run Code Online (Sandbox Code Playgroud)

这是因为翻转所有位并加 1 返回的结果完全相同:

  // Start with -128
  n = 1000 0000
  // Flip bits:
  n = 0111 1111
  // Add 1:
  n = 1000 0000
Run Code Online (Sandbox Code Playgroud)

哎呀!这意味着-(-128) == -128.

这同样适用于乘法和除法:-1 * (-128) == -128。在除法的情况下,结果在某些语言中是不确定的。Go规范并没有留下这种歧义,而是阐明了这种特殊情况:

...如果被除数 x 是 x 的 int 类型的最负值,由于二进制补码整数溢出,商 q = x / -1 等于 x(并且 r = 0)

您可以在 Wikipedia 上找到有关二进制补码算法的更多信息,其中有一节专门介绍最负数