【问题标题】:Two Ways to Interpret Integer Overflow两种解释整数溢出的方法
【发布时间】:2015-01-04 05:02:17
【问题描述】:

我在这里(https://stackoverflow.com/a/27762490/4415632)读到,当整数溢出发生时,最高有效位被简单地切断。

不过,我在这里也读到过(https://stackoverflow.com/a/27747180/3808877),当溢出发生时,“值变成了该类型的最小值,重新开始向上计数”。哪一个是正确的,还是两个答案都正确?如果是这样,谁能告诉我为什么这两种解释彼此等价?

【问题讨论】:

    标签: java types short integer-overflow


    【解决方案1】:

    两者都是正确的,这取决于上下文。一种是强制转换的结果,一种是溢出的结果。这些是不同的操作。例如,如果您将 Long.MAX_VALUE 转换为 int,这是一个转换操作

    System.out.println((int) Long.MAX_VALUE); // <-- -1
    

    如果您通过在Integer.MAX_VALUE 上加一来溢出int,那么

    System.out.println(Integer.MAX_VALUE + 1); // <-- Integer.MIN_VALUE
    

    【讨论】:

    • 出于好奇,这两种方法的结果是否相同?我是第二个问题的回答者之一,惊讶地发现接受答案的二进制解释给出了与我编写的小算法相同的结果
    • 两种方法给出相同的结果,因为这两种方法实际上是相同的东西。
    • 其实我认为这对于 MSB 来说是不正确的
    【解决方案2】:

    两种解释都是正确的,因为它们实际上是相同的。

    让我们看看数学,看看为什么。

    Java 将值存储在 byteshortcharintlong 中,格式为 two's complement。 对于byteshortintlong,它是签名的,对于char,它是未签名的二的补码 格式的属性之一是,对于大多数操作,将值解释为 signed 还是 unsigned 都无关紧要。生成的位模式将是相同的。

    为了简短起见,我将使用byte 进行解释,但其他类型的工作原理相同。

    byte 有 8 位。最高位被解释为 sign 位。所以,位模式是这样的:

    snnn nnnn
    

    分成两组,每组 4 位称为 Nibble,在这里执行是为了纯粹的可读性。作为旁注,半字节可以用十六进制数字表示。

    所以一个字节中有 8 位,每个位可以是 0 或 1。这给我们留下了 2^8 = 256 可以存储在 byte 中的不同值。

    以下是一些示例值:

    0000 0000 -> 0
    0000 0001 -> 1
    0000 0010 -> 2
    0100 0000 -> 64
    0111 1111 -> 127
    1000 0000 -> -128
    1111 1110 -> -2
    1111 1111 -> -1
    

    有符号数的 2 的补码值,即符号位已设置,是通过取 8 位的正值并减去范围来创建的,即在一个字节的情况下减去 256。

    现在让我们看看如果你把-1 加上1 会发生什么。

         1111 1111 -1 / 255
    +    0000 0001  1
    --------------
    = 1  0000 0000 -0 / 256 intermediate result
    =    0000 0000  0 / 256 result after dropping excess leading bits
    

    有溢出。结果现在需要 9 位,但字节只有 8 位,所以最重要的位丢失了。

    让我们看另一个例子,-1 加上-1

         1111 1111 -1 / 255
    +    1111 1111 -1 / 255
    --------------
    = 1  1111 1110 -2 / 510 intermediate result
    =    1111 1110 -2 / 254 result after dropping excess leading bits
    

    或者这个,127 加上5

         0111 1111 127
    +    0000 0101 5
    --------------
    =    1000 0100 132 / -124
    

    正如我们所见,前导位被丢弃了,这实际上是导致“再次从最小值开始计数”而导致其溢出的原因。

    【讨论】:

      【解决方案3】:

      我添加了另一个选项:处理器陷阱。一些处理器会在整数溢出时产生陷阱。如果可用,通常可以通过在处理器状态寄存器中设置一个位在用户模式下启用此功能。

      【讨论】:

      • 好的,现在向我们展示如何以与 JVM 兼容的方式做到这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 2015-03-30
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      相关资源
      最近更新 更多