打破你的認知,Java除以0一定會崩潰嗎?

作者:安卓開發大叔

鏈接:

https://blog.csdn.net/jiese1990/article/details/106608436/

在這個浮躁的社會,我們都學會了一種技能,快速學習使用各種開源庫、開源框架。

學習使用各種高端大氣的技術,熱修復、插件化、模塊化、ORM……

這些技能固然重要,但是有時候也要放慢腳步,耐着性子,打打基本功。

不要看不起這些零零碎碎的基礎知識,這些基礎日積月累,慢慢的會讓你跟同事拉開差距。

接下來,我們直奔主題。開始我們的基本功。


代碼1

System.out.println("1/0=" + 1/0);

大叔的靈魂拷問:

上面的代碼會崩潰嗎?如果不會,會輸出什麼呢?

運行直接崩潰。

代碼2

我們再來看一行代碼:

System.out.println("1.0/0=" + 1.0/0);

大叔的靈魂拷問:

會崩潰嗎?如果不會,會輸出什麼呢?

輸出日誌:

 爲什麼

爲什麼浮點數除以0不會崩潰?

我們先說結論:

因爲java的float和double使用了IEEE 754標準。

這個標準規定:浮點數除以0等於正無窮或負無窮。

4.1、Double類的定義

於是我們打開Double這個類來看看。

infinity單詞的意思是:無窮大

NaN是Not a Number的簡稱,也就是非數。

於是,我們發現,正無窮大的定義居然是1.0f/0.0f 負無窮大的定義爲-1.0f/0.0f,非數的定義爲0.0f/0.0f

4.2、代碼段3

我繼續看一個代碼段:

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));
}

大叔的靈魂拷問:

上面的代碼段會輸出什麼呢?

運行結果:

4.3 接着,我們來看看,java語言規範( Java Language Specification)

https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3

注意關鍵詞1:

IEEE 754

java的單精浮點數float和雙精浮點數double,符合IEEE 754標準。

IEEE 754:二進制浮點數算術標準 ,這個標準描述了浮點數的存儲以及處理的一些規範。

關於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

注意關鍵詞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的定義。

我們把這個文檔往下翻一些,會發現這麼一句:

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 等於負無窮大

於是我們明白,浮點數除以0並不會崩潰,是符合IEEE 754規範。

也正是因爲 IEEE 754的規範就是這麼規定的,所以java才這麼實現的。

下面這段來自,維基百科,https://en.wikipedia.org/wiki/Division_by_zero

 有什麼用呢

我們即使知道了,浮點數除以0不會崩潰,知道了IEEE標準,有什麼用呢?

很多人都會覺得,費這麼大勁,理解了,浮點數除以0不會崩潰,能有什麼用呢?平時我們寫代碼都不會除以0。這麼騷的操作,我纔不會這麼幹。

是的,這個操作是有點騷,你不會這麼幹並不代表其他同事不會這麼做。而且很可能你這麼幹了自己不知道。

在我們寫業務代碼的時候,這個知識點,很少很少能用上。

但是當我們剛好遇到除以0導致的bug的時候,這個時候就非常有用。

尤其像android的app,用戶在線上遇到的bug,我們無法復現,只能通過日誌去分析排查時;

這個時候每個程序員都是福爾摩斯,根據一行行日誌線索,配合實際代碼,排查問題的可能性。

如果我們的認知是錯誤的,任何數除以0都會崩潰,那麼我們的分析將會直接繞過真相去推理。於是得出結論,怎麼可能有bug,不可能的。

於是浪費了很多時間,去收集線索,去推翻我們固有的認知,才能找到真相。

假如我們一開始就有正確的常識,我們就會少走很多彎路。

大叔給大家,講一個工作中真實的故事:

有位同事寫了這麼一段代碼

/**
* 速度換算 米/秒
* @param distance 距離,單位米
* @param time 時間,單位秒
*/
float computeSpeed(float distance, long time){
  return distance/time;
}

然後有一天突然某同事從另一個進程獲取到數據傳入這個函數。

再然後,突然有一天發現,速度顯示一串很奇怪的數字。

於是……接下來的故事,便如你們所想。

原本1小時就解決的bug,花了5個小時。

也正如,blog開頭的引言所表達的。不要小看這些零零碎碎的知識點。

關注我獲取更多知識或者投稿

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章