java中float和double的大小比較

float說明

  • 在Java中float爲單精度小數,佔4個字節空間,其中1爲表示符號位,8爲表示指數爲,剩下23位表示小數位。舉個例子:1.234*1012 ,其中1.234爲指數表示的小數位,12表示指數位(科學表示法中的指數學法),所以小數爲23位在計算機中的大小爲0~223,十進制範圍則是:0~8388608,最多表示7爲數小數,嚴格來說甚至只能表示6爲的準確,因爲0~223的十進制返回不是0 ~ 9999999。所以超過0 ~ 8388608的小數部分在計算機存儲的float中會發生截取現象,導致與實際輸入的大小不符的錯誤。
    下面我們通過一個測試代碼來測試結果:
public class Test{

    public static void main(String[] args) {
		float f = 1/3f;
		System.out.println("1/3f = " + 1/3f);
		System.out.println("(1/3f == 0.3333334f) = " + (1f/3f == 0.3333334f));
		f +=1;
		System.out.println("f = " + f);
		System.out.println("f = " + (f - 1));
		System.out.println("1/3f = " + (1f/3f == f - 1));
    }

輸出log如下:

1/3f = 0.33333334
(1/3f == 0.33333334f) = true
f = 1.3333334
f = 0.33333337
1/3f = false
  • 首先分析第一行輸出,1/3f最後返回float類型的小數,結果爲0.3333334,轉爲指數寫法則爲3.333334*10-1,小數爲8位,其中前七位在準確範圍內,第八位4不在,所以第八位是取得近似值。
  • 接下來是第二行的輸出,直接比較,由於比較的值剛好等於第一行的輸出的結果,所以在計算機內部轉爲2進制後數據相等。
  • 第三行是+1後的結果,我們發現小數位數還是8位,但是由於前面多了一個1,所以後面相應的少了一個3,符合float的精度結果,但是此時我們發現,數據其實已經存在了精度的丟失
  • 第四行-1則是回覆+1之前的狀態,發現此時小數位的狀態已經發生改變,並且此時的值和+1之前的值已經不一致,但是按照正常邏輯來說,+1之後再-1數值應該是不可變的。所以在float計算過程中存在精度的問題。
  • 和上一行一樣,直接比較原始計算值與+1後再-1的值是否相等

根據上面的實驗分析可以得出,float數值的等於比較實用==是不可靠的。因爲存在精度問題,所以float比較相等,都應該在指定的精度範圍內比較,才具備可操作性,例如以下代碼:


public class Test{
		private static final float PRECISION = 0.000001f;
		private static final float PRECISION2 = 0.00001f;
		private static final float PRECISION3 = PRECISION * 10000;

    public static void main(String[] args) {
		float f = 1/3f;
		System.out.println("1/3f = " + 1/3f);
		f +=1;
		System.out.println("f = " + f);
		System.out.println("f = " + (f - 1));
		System.out.println("(1f/3f + 1) - f = " + ((1f/3f + 1) - f < PRECISION));
		System.out.println("1f/3f - (f - 1) = " + (1f/3f - (f - 1) < PRECISION2));
		float f2 = 10000f/3f;
		System.out.println("10000f/3f = " + f2);
		System.out.println("10000f/3f - (f2 - 1) = " + ((10000f/3f -1) - (f2 - 1) < PRECISION3));
        executors.shutdown();
    }
}

輸出結果:

1/3f = 0.33333334
f = 1.3333334
f = 0.33333337
(1f/3f + 1) - f = true
1f/3f - (f - 1) = true
10000f/3f = 3333.3333
10000f/3f - (f2 - 1) = true

對比上一個實驗,我們此時比較大小都是在指定的精度範圍內比較的,所以都是相等。因爲對於超出精度範圍的值,我們無法控制其值的大小,所以對於超出精度範圍的比較沒有實際意義,另外最後有個10000f/3f的大小比較是爲了說明,精度範圍是隨着要比較的float目標值大小而改變的。

double說明

  • double值俗稱雙精度,與float非常相似,區別僅在於double的大小爲8個字節,其中1個符號爲,11位指數位,52位小數位,所以其小數爲返回爲0~252, 十進制範圍爲0~4 503 599 627 370 496,攻擊16位,百分百保證精度的小數位數爲17位。等於比較也是在指定精度範圍內才具有比較意義。

代碼中的使用

所以平時涉及到小數使用,特別是要求精確範圍使用時,一般保留兩位小數時,存儲和計算都會默認使用整數,在實際顯示的時候再除以100,得到精確的兩位小數(比如商品價格)。在金融領域,一般要求精度較高,都會是由BigDecimal來計算大小,避免因爲精度產生的誤差。

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