數學運算是計算機的基本用途之一,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。