几周前刚开始学习 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溢出?
它不是用于溢出的特殊值,它只是一个有符号的 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 上找到有关二进制补码算法的更多信息,其中有一节专门介绍最负数。
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           72 次  |  
        
|   最近记录:  |