《Java从入门到失业》第三章:基础语法及基本程序结构(五):基本算数运算符(1)

3.7运算符

      数学运算是计算机的基本用途之一,Java提供了很是丰富的运算符来支持。咱们根据运算的特色和性质,把运算符划分为几组:基本算数运算符、自增自减运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其余运算符。下面分别介绍。java

3.7.1基本算数运算符

       在Java中,采用+、-、*、/、%来表示加、减、乘、除、取余(取模),这种运算小学就学过,无需多讲,列表举例以下:学习

运算spa

算式3d

结果(假设a=15,b=10)code

加法blog

a+bci

25数学

减法it

a-bio

5

乘法

a*b

150

除法

a/b

1

取余

a%b

5

运算很是简单,可是仍是有一些问题须要注意,下面分别用实例来讲明。

3.7.1.1类型变化

  咱们看一段代码:

 1 public static void main(String[] args) {  
 2         int a1 = 15;  
 3         double a2 = 15;  
 4         int b = 2;  
 5         int c = 0;  
 6         System.out.println("整数运算:");  
 7         System.out.println("a1 + b = " + (a1 + b));  
 8         System.out.println("a1 - b = " + (a1 - b));  
 9         System.out.println("a1 * b = " + (a1 * b));  
10         System.out.println("a1 / b = " + (a1 / b));  
11         System.out.println("a1 % b = " + (a1 % b));  
12         System.out.println("浮点数运算:");  
13         System.out.println("a2 + b = " + (a2 + b));  
14         System.out.println("a2 - b = " + (a2 - b));  
15         System.out.println("a2 * b = " + (a2 * b));  
16         System.out.println("a2 / b = " + (a2 / b));  
17         System.out.println("a2 % b = " + (a2 % b));  
18     } 
 

运行结果为:

整数运算:  
a1 + b = 17  
a1 - b = 13  
a1 * b = 30  
a1 / b = 7  
a1 % b = 1  
浮点数运算:  
a2 + b = 17.0  
a2 - b = 13.0  
a2 * b = 30.0  
a2 / b = 7.5  
a2 % b = 1.0  
 

咱们看到,整数15/2=7,而浮点数15/7=7.5。在Java中,参与运算的2个数有浮点数时,就会自动将非浮点数变成浮点数来运算。

下面为了节省篇幅,就再也不分别列出代码和结果了。

3.7.1.2被0除问题

0.0 / 0 = NaN  
1.0 / 0 = Infinity  
-1.0 / 0 = -Infinity  
1 / 0 =   
Exception in thread "main" java.lang.ArithmeticException: / by zero  
    at ch03.JibenYunsuanfu.main(JibenYunsuanfu.java:16) 

咱们看到,浮点数0除以0,获得NaN;正负浮点数除以0获得正负无穷大;整数除以0会抛出异常。

3.7.1.3原码反码补码

       咱们知道,Java的整型和浮点型都是有范围的,若是运算结果超过范围怎么办呢?咱们知道int型的最大值是214783647,假如咱们+1会获得什么结果呢?结果为:

2147483647 + 1 = -2147483648

说明这个问题缘由以前,得先学习原码、反码、补码的相关知识。

3.7.1.3.1原码

  咱们现实生活当中,能够用正负号来表示正负数,可是计算机中只有0和1,怎么表示正负数呢?因而想出了一个办法,对于固定字长n的二进制数,把2n个数划分为正负数,把最高位规定为符号位,0表明正,1表明负,剩下的二进制数对应十进制数的绝对值。例如假设字长为3,那么一共表示8个数:

十进制

二进制

3

011

2

010

1

001

0

000

-0

100

-1

101

-2

110

-3

111

这种规定叫作“原码”,即3的原码是011,-3的原码是111。看起来很完美吧,可是有2个问题:

  • 0的表示不惟一
  • 没法将减法转换为加法

0的表示不惟一一目了然,为何不能将减法转换为加法?咱们看个例子:

2 - 1 = 2 + (-1) = 010 + 101 = 111 = -3(正确结果为1)

结果错误。那么又为何要把减法转换为加法呢?咱们学习过计算机组成,知道CPU中只有加法寄存器,由于计算机中处理加法比较简单,若是要直接处理减法,须要增长逻辑部件,并且处理减法有借位问题很麻烦。所以在计算机中用原码来进行运算和存储行不通。

3.7.1.3.2反码

       还有别的办法吗?人们又发明了“反码”。反码规定:正数的反码和原码一致,负数的反码为该数对应的绝对值的原码按位取反。假设字长为3,原码反码分别以下:

十进制

原码

反码

3

011

011

2

010

010

1

001

001

0

000

000

-0

100

111

-1

101

110

-2

110

101

-3

111

100

反码解决了减法转换为加法的问题,可是额外须要多一个规定,就是当发生溢出时,须要对最低位加1。咱们看2个例子:

1 – 1 = 1 + (-1) = 001 + 110 = 111 =-0
2 - 1 = 2 + (-1) = 010 + 110 = 1000,溢出了,去掉溢出位后需再加1即000 + 001 = 001 = 1

咱们看到,结果都正确。可是仍是存在2个问题:

  • 0的表示不惟一
  • 减法转加法,须要判断溢出问题
3.7.1.3.3补码

继续探讨,因而出现“补码”。补码规定正数的补码和原码一致,负数的补码为该数对应的绝对值按位取反后加1(若是溢出丢弃最高位)

十进制

原码

反码

补码

3

011

011

011

2

010

010

010

1

001

001

001

0

000

000

000

-0

100

111

000

-1

101

110

111

-2

110

101

110

-3

111

100

101

咱们发现0的表示惟一了。另外用补码计算减法也很简单了,直接转换便可(溢出直接丢弃最高位),咱们看2个例子:

1 – 1 = 1 + (-1) = 001 + 111 = 1000 = 000 = 0
2 - 1 = 2 + (-1) = 010 + 111 = 1001 = 001 = 1

喜欢钻牛角尖的同窗就会问了,为何使用补码就能够解决这些问题呢?有什么道理吗?我就知道你会问,还好我也恶补了这段知识,下面咱们来研究一下。

3.7.1.3.4补码原理

       咱们知道,对于一个3位的二进制,对应的十进制为0-7,一共8个。7+1=111+000=1000,去掉溢出位,又变成000即0。咱们能够说这8个数字造成了一个闭环。这其实对应数学中的一个概念:模。

  模是指一个计量系统的计数范围,例如咱们熟悉的时钟,它的计数范围是0-11,模是12。计算机也能够当作一个计量机器,由于计算机的字长是定长的,即存储和处理的位数是有限的,所以它也有一个计量范围,即都存在一个“模”。对于字长3位的机器来讲,计数范围是0-7,模是8。“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,都可化减法为加法运算。

  咱们以时钟为例:当前时间是2点,逆时针拨2格变成0点。顺时针拨10格也是0点。假设逆时针叫减,顺时针叫加,那么对于模12的系统里,减2和加10的效果同样。事实上,减3和加9,减4和加8效果也同样。咱们把2和十、3和九、4和8互称为补数,特色就是两者相加等于模。所以在有模的系统里,减去一个数,能够变成加上它的补数,便可以把减法变成加法。

回到3位数的二进制以下图:

咱们很容易就知道模为8,1和七、2和六、3和五、4和4他们互为补数。列一个表:

减数

补数

1

7

2

6

3

5

4

4

5

3

6

2

7

1

可是问题来了,3位二进制系统里,虽然减n能够变成加n,可是因为没有负数,所以计算减法,须要先计算减数的补数,例如减1,须要计算1的补数8-1。怎么办?聪明的你必定能够想到,补数都是成对的,咱们把成对的补数中的一半规定为负数是否是就能够了?例如a-1=a+(-1)=a+7,假如咱们规定7的二进制111表明-1,那么在计算的时候就没有减法了。同理咱们还能够规定110表明-2,101表明-3。至于100是表明4仍是-4,均可以,通常咱们选择表明-4。这样一来,对于3位二进制系统,表示数的范围就变成-4~3,而全部的减法就变成加法了。并且这样一来咱们还惊奇的发现:

  • 全部的正数最高位都是0,负数最高位都是1
  • 全部负数的二进制都是它所对应的绝对值的二进制按位取反后+1,就是补码

到此为止,咱们就搞清楚了为何在计算中要用补码来表示负数了。

  最后,咱们回到开头的例子:

2147483647 + 1 = -2147483648 

如今回答这个问题太easy了。在Java中,一个数字若是不加后缀,默认就是int型的。咱们知道int型占用4个字节,则int的系统是一个模为232的系统。而后采用补码规则存储,这样最大的正数是231-1=2147483647。这个数再加1就变成231。231的补数是它本身,可是因为231的二进制最高位是1,咱们习惯把它规定为负数,即-231,所以就是-2147483648。

相关文章
相关标签/搜索