Java浮點數詳解(double float)-- 分分搞定浮點數

初學Java只簡單聽說double,float是不能精確的表示一個數钻注,然后留下滿滿的疑問篮撑? why? 這個問題已經放了好久時間了逞壁,今天終于把這個問題整明白了!首先整理一下以下幾個困惑


1.浮點數(double? float)真的會不精確绍弟?

我們在使用的過程中并沒有誤差凹技础?

double a = 0.4;

double b = a*4;

System.out.println(b); // 輸出 1.6

// 不是說浮點數不精確嗎樟遣?那我們做一個相等判斷

System.out.println(a == 0.4); //輸出 true

// 我去而叼,哪有什么不精確!1葵陵!瞎BB

當我們放心大膽的用浮點數時

System.out.println (0.4 * 0.2);

// 輸出 0.08000000000000002

System.out.println(40000000.0f == 40000000.5f); // float類型字面量

// 輸出 true

System.out.println(4000000000000000.0 == 4000000000000000.2);

// 輸出 true

// 啊西巴! 什么情況

2.浮點數為什么會不精確?

粗淺的解釋:

1. double 的取值范圍 [-1.79 e+308 , 1.79 e+308] 瞻佛。但 double 的存儲空間為 8 字節(jié)一共 64 位脱篙,也就是說 double 最多可以用 2∧64 個不同值來表示不同區(qū)間,約等于 1.84 e+19 個區(qū)間伤柄。

這也是為什么 40000000.0 f = 40000000.5 f绊困, 4000000000000000.0 = 4000000000000000.2 ,因為他們在同一個區(qū)間适刀。

2. 每一個區(qū)間都會用一個值來顯示秤朗,但這個顯示值(在這個區(qū)間的值都用這個值顯示)與存儲值(存儲在計算機中二進制所表示的值)并不一定相等。(“ 整數 ” 顯示值 = 儲存值笔喉,所以下面只討論 “ 小數 ”)


顯示值? (double) ??儲存值 (double)

0.5 ? ? 0.5

0.4 ? ? 0.40000000000000002220446049250313080847263336181640625

0.25 ? ?0.25

0.2 ? ? 0.200000000000000011102230246251565404236316680908203125


什么時候 顯示值 會與 儲存值 相等呢取视? 這里有一個規(guī)律

有一個小于 1 的小數 d 硝皂,如果滿足 d*2∧n = 1 則 d 的 顯示值 等與 儲存值 。( n 為正整數)?

比如: ?? ? ? ? ? ? ??0.5 * 2 = 1 ,? ? ? ? ? ? ? ?0.25 * 2 * 2 ?= 1 , ? ? ? ? ? ? 0.125 * 2 * 2 * 2 = 1

為什么會有這個規(guī)律贫途,可以了解小數的二進制表示 吧彪。

計算和比較時用的是 儲存值,最終以 計算結果所在區(qū)間的 顯示值 顯示在屏幕上丢早;


顯示值? (double) ? ?儲存值 (double)

0.4 ? ? ?0.40000000000000002220446049250313080847263336181640625

0.2 ? ? ?0.200000000000000011102230246251565404236316680908203125


接下來我們可以解釋:0.4 ? * ? 0.2 ? = ? 0.08000000000000002?

a? = (0.4的儲存值) 0.40000000000000002220446049250313080847263336181640625;

b? = (0.2的儲存值) 0.200000000000000011102230246251565404236316680908203125;

a * b ≈ 0.08000000000000000888178419700125256990808622629275169;

計算結果需要存儲,它所在區(qū)間對應的?儲存值?為 :

0.080000000000000015543122344752191565930843353271484375

該?存儲值 對應的 顯示值 為:

0.08000000000000002

3.誤差累積效應(重點)

浮點數因為計算時是用?儲存值 多次計算秧倾,有可能會放大誤差怨酝。

System.out.println(0.4 * 0.4 * 0.4); // 輸出 0.06400000000000002

System.out.println(0.5 * 0.5 * 0.5); // 輸出 0.125

注意是有可能不是一定,有兩種情況那先;

1. (顯示值? =? 儲存值) 农猬,這樣多次計算沒有誤差,除非計算中出現數值的有效位數過長售淡,double類型不能表示斤葱,會出現精度丟失的情況

2. (顯示值? >? 儲存值) 與 (顯示值? < ?儲存值)混合運算,它們的誤差會相互抵消

3.浮點數使用場景

一般來說浮點數使用比較方便揖闸,誤差比較小( 可以忽略 )揍堕,計算機操作浮點數的效率高( 與BigDecimal相比較),所以浮點數挺常用的汤纸。但使用它必須?慎重?考慮以下情況:

1. 數值的有效位數過長衩茸,會發(fā)生精度丟失;

2. 數值較大贮泞,誤差也會變大了楞慈;

? ? 0.40000000000000000000000? ? =? ? 0.40000000000000002220446

(在同一個區(qū)間,儲存值都為 ?0.40000000000000002220446049250313080847263336181640625 ?所以相等)

? ? 40000000000000000000000.0 ? ? = ? 40000000000000002220446.0

(在同一個區(qū)間啃擦,儲存值都為? 40000000000000000000000? 所以相等)

3. 浮點數的?誤差累積效應囊蓝;

4. 該數值表示的類型是否對誤差有嚴格的要求,(比如:時間令蛉,金錢)

4.該如何進行精確的計算

Java要進行精確計算聚霜,需要使用到類java.math.Big。借助BigDecima可以查看浮點數的儲存值言询;

BigDecimal b1 = new BigDecimal( 0.4 ); // double類型字面量

BigDecimal b2 = new BigDecimal( 0.4f ); // float類型字面量

System.out.println( b1 ); // 輸出 0.40000000000000002220446049250313080847263336181640625

System.out.println( b2 ); // 輸出 0.4000000059604644775390625

哇卡卡俯萎,通過上面的案例,可以發(fā)現 BigDecima 真強大T撕肌夫啊!不過用它做計算有點麻煩

publicBigDecimal add(BigDecimal value);//加法

publicBigDecimal subtract(BigDecimal value);//減法

publicBigDecimal multiply(BigDecimal value);//乘法

publicBigDecimal divide(BigDecimal value);//除法

BigDecimal b1 = new BigDecimal("0.4");

BigDecimal b2 = new BigDecimal("0.2");

System.out.println(b1.add(b2)); // 輸出 0.6

System.out.println(b1.subtract(b2)); // 輸出 0.2

System.out.println(b1.multiply(b2)); // 輸出 0.08

System.out.println(b1.divide(b2)); // 輸出 2

若要詳細了解BigDecima,請查看API辆憔。



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末撇眯,一起剝皮案震驚了整個濱河市报嵌,隨后出現的幾起案子,更是在濱河造成了極大的恐慌熊榛,老刑警劉巖锚国,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異玄坦,居然都是意外死亡血筑,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門煎楣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豺总,“玉大人,你說我怎么就攤上這事择懂∮髟” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵困曙,是天一觀的道長表伦。 經常有香客問我,道長慷丽,這世上最難降的妖魔是什么蹦哼? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮盈魁,結果婚禮上翔怎,老公的妹妹穿的比我還像新娘。我一直安慰自己杨耙,他們只是感情好赤套,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著珊膜,像睡著了一般容握。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上车柠,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天剔氏,我揣著相機與錄音,去河邊找鬼竹祷。 笑死谈跛,一個胖子當著我的面吹牛,可吹牛的內容都是我干的塑陵。 我是一名探鬼主播感憾,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼令花!你這毒婦竟也來了阻桅?” 一聲冷哼從身側響起凉倚,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫂沉,沒想到半個月后稽寒,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡趟章,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年杏糙,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尤揣。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡搔啊,死狀恐怖,靈堂內的尸體忽然破棺而出北戏,到底是詐尸還是另有隱情,我是刑警寧澤漫蛔,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布嗜愈,位于F島的核電站,受9級特大地震影響莽龟,放射性物質發(fā)生泄漏蠕嫁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一毯盈、第九天 我趴在偏房一處隱蔽的房頂上張望剃毒。 院中可真熱鬧,春花似錦搂赋、人聲如沸赘阀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽基公。三九已至,卻和暖如春宋欺,著一層夾襖步出監(jiān)牢的瞬間轰豆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工齿诞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酸休,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓祷杈,卻偏偏與公主長得像斑司,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吠式,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容