打破你的認(rèn)知,Java除以0一定會(huì)崩潰嗎?
? ? ?
? ?正文? ?
在這個(gè)浮躁的社會(huì),我們都學(xué)會(huì)了一種技能,快速學(xué)習(xí)使用各種開源庫、開源框架。
學(xué)習(xí)使用各種高端大氣的技術(shù),熱修復(fù)、插件化、模塊化、ORM……
這些技能固然重要,但是有時(shí)候也要放慢腳步,耐著性子,打打基本功。
不要看不起這些零零碎碎的基礎(chǔ)知識,這些基礎(chǔ)日積月累,慢慢的會(huì)讓你跟同事拉開差距。
接下來,我們直奔主題。開始我們的基本功。
System.out.println("1/0="?+?1/0);
大叔的靈魂拷問:
上面的代碼會(huì)崩潰嗎?如果不會(huì),會(huì)輸出什么呢?
運(yùn)行直接崩潰。

我們再來看一行代碼:
System.out.println("1.0/0="?+?1.0/0);
大叔的靈魂拷問:
會(huì)崩潰嗎?如果不會(huì),會(huì)輸出什么呢?
輸出日志:

為什么浮點(diǎn)數(shù)除以0不會(huì)崩潰?
我們先說結(jié)論:
因?yàn)閖ava的float和double使用了IEEE 754標(biāo)準(zhǔn)。
這個(gè)標(biāo)準(zhǔn)規(guī)定:浮點(diǎn)數(shù)除以0等于正無窮或負(fù)無窮。
4.1、Double類的定義
于是我們打開Double這個(gè)類來看看。

infinity單詞的意思是:無窮大
NaN是Not a Number的簡稱,也就是非數(shù)。
于是,我們發(fā)現(xiàn),正無窮大的定義居然是1.0f/0.0f?。負(fù)無窮大的定義為-1.0f/0.0f,非數(shù)的定義為0.0f/0.0f
4.2、代碼段3
我繼續(xù)看一個(gè)代碼段:
public?static?void?main(String[]?args)?{
??System.out.println("1.0/0="?+?1.0/0);
??System.out.println("-1.0/0="?+?-1.0/0);
??double?positiveInfinity?=?1.0/0;
??double?negativeInfinity?=?-1.0/0;
??System.out.println("(positiveInfinity==negativeInfinity)="?+?(positiveInfinity==negativeInfinity));
??System.out.println();
??System.out.println("100.0/0="?+?100.0/0);
??System.out.println("-100.0/0="?+?-100.0/0);
??System.out.println();
??System.out.println("0.0/0="?+?0.0/0);
??System.out.println("(-0.0==0.0)="?+?(-0.0==0.0));
}
大叔的靈魂拷問:
上面的代碼段會(huì)輸出什么呢?
運(yùn)行結(jié)果:

4.3 接著,我們來看看,java語言規(guī)范( Java Language Specification)
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3

注意關(guān)鍵詞1:
IEEE 754
java的單精浮點(diǎn)數(shù)float和雙精浮點(diǎn)數(shù)double,符合IEEE 754標(biāo)準(zhǔn)。
搜索公眾號程序員小樂回復(fù)關(guān)鍵字“offer”,獲取算法面試題和答案。
IEEE 754:二進(jìn)制浮點(diǎn)數(shù)算術(shù)標(biāo)準(zhǔn)?,這個(gè)標(biāo)準(zhǔn)描述了浮點(diǎn)數(shù)的存儲(chǔ)以及處理的一些規(guī)范。
關(guān)于IEEE754,百度百科
https://baike.baidu.com/item/IEEE%20754/3869922?fromtitle=IEEE754%E6%A0%87%E5%87%86
IEEE-754 references
https://web.archive.org/web/20070505021348/http://babbage.cs.qc.edu/courses/cs341/IEEE-754references.html
注意關(guān)鍵詞2
A NaN value is used to represent the result of certain invalid operations such as dividing zero by zero.
翻譯過來的就是:NaN = 0.0/0.0
這也就是我們看到Double類里面NaN的定義。
我們把這個(gè)文檔往下翻一些,會(huì)發(fā)現(xiàn)這么一句:

for example, 1.0/0.0 has the value positive infinity, while the value of 1.0/-0.0 is negative infinity.
翻譯成中文:1.0/0.0 等于正無窮大,1.0/-0.0 等于負(fù)無窮大
于是我們明白,浮點(diǎn)數(shù)除以0并不會(huì)崩潰,是符合IEEE 754規(guī)范。
也正是因?yàn)?IEEE 754的規(guī)范就是這么規(guī)定的,所以java才這么實(shí)現(xiàn)的。
下面這段來自,維基百科,https://en.wikipedia.org/wiki/Division_by_zero

我們即使知道了,浮點(diǎn)數(shù)除以0不會(huì)崩潰,知道了IEEE標(biāo)準(zhǔn),有什么用呢?
很多人都會(huì)覺得,費(fèi)這么大勁,理解了,浮點(diǎn)數(shù)除以0不會(huì)崩潰,能有什么用呢?平時(shí)我們寫代碼都不會(huì)除以0。這么騷的操作,我才不會(huì)這么干。
是的,這個(gè)操作是有點(diǎn)騷,你不會(huì)這么干并不代表其他同事不會(huì)這么做。而且很可能你這么干了自己不知道。
在我們寫業(yè)務(wù)代碼的時(shí)候,這個(gè)知識點(diǎn),很少很少能用上。
但是當(dāng)我們剛好遇到除以0導(dǎo)致的bug的時(shí)候,這個(gè)時(shí)候就非常有用。
尤其像android的app,用戶在線上遇到的bug,我們無法復(fù)現(xiàn),只能通過日志去分析排查時(shí);
這個(gè)時(shí)候每個(gè)程序員都是福爾摩斯,根據(jù)一行行日志線索,配合實(shí)際代碼,排查問題的可能性。
如果我們的認(rèn)知是錯(cuò)誤的,任何數(shù)除以0都會(huì)崩潰,那么我們的分析將會(huì)直接繞過真相去推理。于是得出結(jié)論,怎么可能有bug,不可能的。
于是浪費(fèi)了很多時(shí)間,去收集線索,去推翻我們固有的認(rèn)知,才能找到真相。
假如我們一開始就有正確的常識,我們就會(huì)少走很多彎路。
大叔給大家,講一個(gè)工作中真實(shí)的故事:
有位同事寫了這么一段代碼
/**
*?速度換算?米/秒
*?@param?distance?距離,單位米
*?@param?time?時(shí)間,單位秒
*/
float?computeSpeed(float?distance,?long?time){
??return?distance/time;
}
然后有一天突然某同事從另一個(gè)進(jìn)程獲取到數(shù)據(jù)傳入這個(gè)函數(shù)。
再然后,突然有一天發(fā)現(xiàn),速度顯示一串很奇怪的數(shù)字。
于是……接下來的故事,便如你們所想。
原本1小時(shí)就解決的bug,花了5個(gè)小時(shí)。
也正如,blog開頭的引言所表達(dá)的。不要小看這些零零碎碎的知識點(diǎn)。
參考資料:
https://juejin.im/post/5edcc957e51d4578801683c0
關(guān)于IEEE754,百度百科
IEEE-754 references
https://stackoverflow.com/questions/12954193/why-does-division-by-zero-with-floating-point-or-double-precision-numbers-not
來源:blog.csdn.net/jiese1990/article/details/106608436/
版權(quán)申明:內(nèi)容來源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無法確認(rèn),我們都會(huì)標(biāo)明作者及出處,如有侵權(quán)煩請告知,我們會(huì)立即刪除并表示歉意。謝謝!

