java - ^32 限制和模方法

标签 java

在 Java 中,整数必须介于 2^31 - 1 到 -2^31 之间

所以如果 int x = 2 * 1500000000

逻辑答案将是 300000000 但因为它的值有限制,因此将其向前推进并使用 2^32 mod 3000000000 它将是 -1294967296 但因为它向前推进,数字将变为负数,因为正数字段已溢出。我说这是真的吗?

此外,我还搜索并阅读了调制部分,例如在时钟中 15 mod 12 == 3 因为它是除法的余数,但它很适合作为时钟的示例,因为 12 在这里是一个常数。

那么2^32是所有整数调制计算溢出的常数吗?

最佳答案

为了简单起见,我将使用 8 位整数。

在二进制中,8 位范围从 00000000b11111111b

00000000b = 0d
11111111b = 255d

那么计算机如何给整数加符号呢?这是two's complement .

对于无符号整数,我们通过以下方式将 11111111b 从二进制转换为十进制:

  11111111b
= 1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 1*128 + 1*64  + 1*32  + 1*16  + 1*8   + 1*4   + 1*2   + 1*1
= 255d

那么有符号整数11111111b怎么样?这是一个简单的方法:

  v----------(sign flag 1=negative)
  11111111b
= 1*(-2^7) + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 1*(-128) + 1*64  + 1*32  + 1*16  + 1*8   + 1*4   + 1*2   + 1*1
= -1d

一般来说,有符号数的最高有效位是符号标志。

要将负十进制数转换为二进制补码:

 -18d
 ========
 without sign     0001 0010
 one's complement 1110 1101 (inverted)
*two's complement 1110 1110 (one's complement + 1)

8位有符号整数的范围是从-2^72^7-1

现在什么是溢出?让我们看看:

  01111111b
= 127d

  01111111b + 1
= 10000000b
= 1*(-2^7) + 0*2^6 + 0*2^5 + 0*2^4 + 0*2^3 + 0*2^2 + 0*2^1 + 0*2^0
= 1*(-128) + 0*64  + 0*32  + 0*16  + 0*8   + 0*4   + 0*2   + 0*1
= -128d

  127d + 1d
  =========
  0111 1111 (127d)  +
 +0000 0001 (1d)    +
 ----------
  1000 0000 (-128d) - (overflow)

因此,如果我们将最大的 8 位有符号整数加 1,结果就是最小的 8 位有符号整数。 +ve++ve -> -ve 是一个溢出错误。

减法怎么样? 45-16? (+ve + -ve -> +ve)

  45d - 16d
  =========
  0010 1101 (45d)   +
 +1111 0000 (-16d)  -
 ----------
1 0001 1101 (29d)   +
^---------------------(discard)

45-64 怎么样? (+ve + -ve -> -ve)

  45d - 64d
  =========
  0010 1101 (45d)   +
 +1100 0000 (-64d)  -
 ----------
  1110 1101 (-19d)  -

-64-64 怎么样? (-ve + -ve -> -ve)

  -64d - 65d
  =========
  1100 0000 (-64d)  -
 +1100 0000 (-64d)  -
 ----------
1 1000 0000 (-128d) +
^---------------------(discard)

-64-65怎么样?

  -64d - 65d
  =========
  1100 0000 (-64d)  -
 +1011 1111 (-65d)  -
 ----------
1 0111 1111 (127d)  + (underflow)
^---------------------(discard)

所以 -ve + -ve -> +ve 是一个下溢错误。

32 位整数的情况类似,只是可用位数更多。

对于您的问题2*1500000000,如果我们将它们视为32位无符号整数,则结果为3000000000,其二进制表示为:

  1011 0010 1101 0000 0101 1110 0000 0000
= 1*2^31 + 0*2^30 + ...
= 1*2147483648 + 0*1073741824 + ...
= 3000000000d

但是如果我们将其视为 32 位有符号整数:

  v------(Let's recall this is the sign flag)
  1011 0010 1101 0000 0101 1110 0000 0000
= 1*(-2^31) + 0*2^30 + ...
= 1*(-2147483648) + 0*1073741824 + ...
= -1294967296d
<小时/>

添加:无符号整数溢出

无符号整数的溢出非常相似:

  11111111b
= 255d

  11111111b + 1
= 00000000b
= 0d

  255d + 1d
  =========
  1111 1111 (255d)  +
 +0000 0001 (1d)    +
 ----------
1 0000 0000 (0d)    - (overflow)
^---------------------(discard)

这就是为什么对于 32 位无符号整数,它始终是 mod 2^32

顺便说一句,这不仅适用于 Java,也适用于大多数编程语言,例如 C/C++。其他一些编程语言可能会自动处理溢出并将类型更改为更高精度或浮点,例如 PHP/JavaScript。

关于java - ^32 限制和模方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11281703/

相关文章:

java - 尝试编译时出现错误找不到符号

java - Spring 4 @AutoWired 失败

java - 在另一个线程中下载文件并等待主线程中的进度会卡住 JFrame 的渲染

java - 每次Windows启动时安排任务的vbs代码是什么?

java - JAX-WS(TomEE) Web 服务构造函数仅运行一次

java - 为什么byte的最大值加一,却没有溢出

java - 如何修改Maven导入的属性文件

具有现有类的 Java 泛型

java - Oracle JDK 公共(public)更新到 01/31/2019 还是 01/01/2019?

java - 如何使用java中的线程实例化多个带有动画的JFrame?