容易忽視的基礎——浮點精度

首先看下下面的題目html

public static void main(String[] args) {
		float a = 1.0f;
		float b = 0.9f;
		float c = 0.8f;
		System.out.println((a-b)==(b-c));
	}
複製代碼

請問控制檯輸出的結果是:java

A. trueapi

B. false安全

不知道各位同窗是怎麼選的,換作以前的我確定堅決果斷的選擇A了。可是,在ide中運行一下後控制檯給出的結果是false。爲啥呢?bash

浮點精度

浮點型數據類型,FLOAT 數據類型用於存儲單精度浮點數或雙精度浮點數。浮點數使用 IEEE(電氣和電子工程師協會)格式。浮點類型的單精度值具備 4 個字節,包括一個符號位、一個 8 位 excess-127 二進制指數和一個 23 位尾數。尾數表示一個介於 1.0 和 2.0 之間的數。因爲尾數的高順序位始終爲 1,所以它不是以數字形式存儲的。此表示形式爲 float 類型提供了一個大約在 -3.4E+38 和 3.4E+38 之間的範圍。--引自百度oracle

實際上咱們的數字都是由2的冪數來湊成的。就如同上面的題目,兩個減法得出的結果的二進制類似數是不一樣的因此控制檯答應出來的結果是false。ide

下面再舉個開發過程當中遇到的一個坑ui

class Untitled {
	public static void main(String[] args) {
		float a = 3.01f;
		float b = a % 1.0f;
		System.out.println(b);
	}
}

····
0.00999999
複製代碼

沒錯它不是0.01,取模盡然是0.00999999接近1。因此float的運算是不安全的。那咱們如何保證其計算結果不失真呢?spa

這個時候咱們須要利用BigDecimalcode

class Untitled {
	public static void main(String[] args) {
	BigDecimal a =new BigDecimal("3.01");
    BigDecimal b =new BigDecimal("1");
    float c = a.remainder(b).floatValue();
    System.out.println(c);
	}
}

····
0.01
複製代碼

這裏用字符串是由於字符串是按位來存儲的,天然數都是能夠用2進制精確表示的,因此這裏使用字符串來實例化。詳細能夠參考BigDecimal官方文檔

相關文章
相關標籤/搜索