数学运算是计算机的基本用途之一,Java提供了很是丰富的运算符来支持。咱们根据运算的特色和性质,把运算符划分为几组:基本算数运算符、自增自减运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其余运算符。下面分别介绍。java
在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 |
运算很是简单,可是仍是有一些问题须要注意,下面分别用实例来讲明。
咱们看一段代码:
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个数有浮点数时,就会自动将非浮点数变成浮点数来运算。
下面为了节省篇幅,就再也不分别列出代码和结果了。
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会抛出异常。
咱们知道,Java的整型和浮点型都是有范围的,若是运算结果超过范围怎么办呢?咱们知道int型的最大值是214783647,假如咱们+1会获得什么结果呢?结果为:
2147483647 + 1 = -2147483648
说明这个问题缘由以前,得先学习原码、反码、补码的相关知识。
咱们现实生活当中,能够用正负号来表示正负数,可是计算机中只有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的表示不惟一一目了然,为何不能将减法转换为加法?咱们看个例子:
2 - 1 = 2 + (-1) = 010 + 101 = 111 = -3(正确结果为1)
结果错误。那么又为何要把减法转换为加法呢?咱们学习过计算机组成,知道CPU中只有加法寄存器,由于计算机中处理加法比较简单,若是要直接处理减法,须要增长逻辑部件,并且处理减法有借位问题很麻烦。所以在计算机中用原码来进行运算和存储行不通。
还有别的办法吗?人们又发明了“反码”。反码规定:正数的反码和原码一致,负数的反码为该数对应的绝对值的原码按位取反。假设字长为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个问题:
继续探讨,因而出现“补码”。补码规定正数的补码和原码一致,负数的补码为该数对应的绝对值按位取反后加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位的二进制,对应的十进制为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,而全部的减法就变成加法了。并且这样一来咱们还惊奇的发现:
到此为止,咱们就搞清楚了为何在计算中要用补码来表示负数了。
最后,咱们回到开头的例子:
2147483647 + 1 = -2147483648
如今回答这个问题太easy了。在Java中,一个数字若是不加后缀,默认就是int型的。咱们知道int型占用4个字节,则int的系统是一个模为232的系统。而后采用补码规则存储,这样最大的正数是231-1=2147483647。这个数再加1就变成231。231的补数是它本身,可是因为231的二进制最高位是1,咱们习惯把它规定为负数,即-231,所以就是-2147483648。