1. 程式人生 > >Java中不同數值型別間轉換與計算精度丟失問題

Java中不同數值型別間轉換與計算精度丟失問題

在Java程式設計過程中,經常會涉及到不同數值型別之間的計算問題,例如:

int m=6;  
float n=3.5f;  
double p=2.75d;
System.out.println(m + n); 
System.out.println(n + p);

執行程式,輸出結果分別為:9.5和6.25。計算機在執行m+n的時候,首先會將m先轉換成float型別,然後再將其與n進行加法運算。同理,執行n+p時,首先將n轉換成double型別,然後再將其與p進行加法運算。下面我們來看一下實際編碼過程中出現的問題:

我們可以看出,當兩個不同型別的數進行基本運算子操作時,精度小的數值型別首先會向精度大的數值型別進行轉換,最後進行計算。下面來看下數值型別之間的合法轉換圖。

數值型別之間的合法轉換圖

圖中的實線箭頭表示有資訊丟失的轉換,虛線箭頭表示無資訊丟失的轉換。其轉換規則如下:

  • 如果兩個運算元中有一個是double型別,另一個就會轉換為double型別;
  • 否則,如果有一個運算元是float,另一個就會轉化為float;
  • 否則,如果有一個運算元是long,另一個就會轉換為long;
  • 否則,兩個運算元都將轉換為int型別。

    為了理解這些規則,這裡再舉幾個例子:

public class MyJava {

    /**
     * @param args
     */
    public static void main(String[] args) {
        int
a=6; float b=3.5f; double c =5.26d; long d=82l; short e=2; byte f=3; System.out.println(a + b); System.out.println(a + c); System.out.println(a + d); System.out.println(a + e); System.out.println(a + f); System.out.println(b + c); System.out.println(b + d); System.out.println(b + e); System.out.println(b + f); System.out.println(c + d); System.out.println(c + e); System.out.println(c + f); System.out.println(d + e); System.out.println(d + f); System.out.println(e + f); } }

輸出結果為:

9.5
11.26
88
8
9
8.76
85.5
5.5
6.5
87.26
7.26
8.26
84
85
5

接下來我們再看下數值之間計算時候存在的計算精度丟失問題。例子如下所示:

public class MyJava {

    /**
     * @param args
     */
    public static void main(String[] args) {
        int a = 3;
        double b = 0.03;
        double c = 0.03;
        double d = a+b+c;
        System.out.println("d:" + d); 
    }

} 

輸出結果為:

d:3.0599999999999996

這裡我們可以看到最後的結果並不是我們預期的那樣為3.06,其實double型別數值的計算經常會出現這種精度丟失的問題,尤其是有小數點的情況下,常常會應為精度丟失而導致程式出錯。那麼該如何解決這個問題呢?這時候我們需要使用位於java.math包中的BigDecima類並用String來構造。具體使用方法如下:

    /** 
     * @param m1 
     * @param m2 
     * @return 
     */ 
    public static double add(double m1, double m2) {
        BigDecimal p1 = new BigDecimal(Double.toString(m1));
        BigDecimal p2 = new BigDecimal(Double.toString(m2));
        return p1.add(p2).doubleValue();
    }

    /** 
     * @param m1 
     * @param m2 
     * @return 
     */ 
    public static double sub(double m1, double m2) {
        BigDecimal p1 = new BigDecimal(Double.toString(m1));
        BigDecimal p2 = new BigDecimal(Double.toString(m2));
        return p1.subtract(p2).doubleValue();
    }

    /** 
     * @param m1 
     * @param m2 
     * @return 
     */ 
    public static double mul(double m1, double m2) {
        BigDecimal p1 = new BigDecimal(Double.toString(m1));
        BigDecimal p2 = new BigDecimal(Double.toString(m2));
        return p1.multiply(p2).doubleValue();
    }


     /**    
      *   @param   m1  
      *   @param   m2        
      *   @param   scale      
      *   @return     
      */     
    public static double div(double m1, double m2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("Parameter error");
        }
        BigDecimal p1 = new BigDecimal(Double.toString(m1));
        BigDecimal p2 = new BigDecimal(Double.toString(m2));
        return p1.divide(p2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    } 

以上就是問題的處理方法了。

相關推薦

Java不同數值型別轉換計算精度丟失問題

在Java程式設計過程中,經常會涉及到不同數值型別之間的計算問題,例如: int m=6; float n=3.5f; double p=2.75d; System.out.println(m + n); System.out.println(n

java的資料型別轉換形式

   java中的資料型別分為兩種:基本資料型別和引用資料型別;    基本資料型別中包含的就是我們常說的“四類八種”,即 整數型:byte、short、int、long,浮點型:float、double,布林型:boolean,字元型:char 4類8種

java不同資料型別的運算

今天上班的時候,不是很忙,看到java程式設計的群裡發了一個問題:1+‘1’+1+1+“0”,請問等於多少,我相信不少人看到這樣的問題肯定有點蒙,至少我剛開始的時候是懵逼的,很好奇答案到底是什麼,於是

你真的搞明白Java基本資料型別轉換了嗎?

寫這篇部落格源於在進行長連線通訊的時候我們需要將流資料和我們的String、基本型別的資料之間進行轉換,我們知道byte[]與String之間的轉換相當方便,那麼接下來我們就要弄懂byte[]與基本資料型別之間的轉換了。 計算機中的儲存 首先

Java基本資料型別包裝類,字串轉換

儲存範圍大小: byte-short-char-int-long-float-double 低階到高階自動型別轉換: int i = 5; float f = i; double d = i; 高階到低階強制型別轉換: int a = 20; byte b = (byte) a;

java 的date型別和oracle的date型別轉換

//從oracle資料庫中讀出date型別的資料並轉換成java的data型別 SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// HH24小時制,hh是12小時制 mSendTime =

Java數值型別之間轉換的規則

在我們進行數值相關操作的時候,很多時候都會進行不同型別的相關操作:避免不了存在數值型別之間的轉換。 那java中數值型別轉換的規則是什麼呢?有些會不丟失精度轉換,而有些會丟失精度。 1.如果兩個運算元中有一個是double型別,另一個運算元就會轉換為double型別 2.否則,如果其中一

Java 鍵盤錄入Scanner,String Integer資料型別轉換

Scanner的使用 (1)用於鍵盤錄入資料的類。 (2): A:講解了System.in這個東西。 它其實是標準的輸入流,對應於鍵盤錄入 B:常用的格式

JavaFile,byte[],Object轉換

部落格分類:  java基礎及框架 java  一、有兩點需要注意:     1、Object 物件必須是可序列化物件 。    

JavaString和byte[]轉換淺析

Java語言中字串型別和位元組陣列型別相互之間的轉換經常發生,網上的分析及程式碼也比較多,本文將分析總結常規的byte[]和String間的轉換以及十六進位制String和byte[]間相互轉換的原理及實現。 1. String轉byte[] 首先我們來分析一下常規的Strin

R語言將資料框的字元型別數字轉換數值

場景1 我現在有一個數據框datexpr,裡面的數字都是以字元型表示的,像這樣 > datexpr[1,1] [1] " 1.143773961" 現在我想把這個資料框中的字元型數字全部轉為數值型數字 使用下面語句即可 datexpr2=as.data.fra

Java關於基本型別物件包裝器==的問題

這也是最近比較火的一道小題目 不加思索的話往往以為都是true。但是事實不是這樣的 ==運算子也可以應用於物件包裝器物件,只不過檢測的物件是否指向同一區域,所以c==d通常不成立, 然而,Java實現卻有可能讓它成立。 如果將經常出現的值包裝到同一物件中,

JDK8的GC型別 高併發生產環境不同GC型別帶來的效能提升

    記一次專案中,在JDK8環境下,並行GC月併發GC在Restful介面中體現差異。     當今國內第三大流量電商(某多多),博主所在公司在前一段時間和他們有產品合作,他們對我們產品提出了非常嚴格的要求:一分鐘時間範圍內介面響應時間大於300MS的

java的資料型別轉換

一,強制型別轉換        1特點;不能自動完成,程式碼需要特殊格式處理         2格式:範圍小的型別 範圍小的變數名 =(範圍小的型別) 原本範圍大的型別;

Java 的覆蓋@Override註解寫不寫的不同

1、 一般來說,寫與不寫沒什麼區別,JVM可以自識別 2、寫的情況下:即說明子類要覆蓋基類的方法,基類必須存在方法(控制型別public,protected,返回值,引數列表型別)與子類方法完成一致的方法,否則會報錯(找不到被Override的方法)。 3、在不寫@Overrid

java關於static 型別的變數宣告初始化的問題

今天在聊天室看到這樣一個問題,剛是感覺頭腦一下 懵住了,現在簡單整理一下,希望能對像我一樣的廣大菜鳥們解一份疑、答一份惑! 【問題】static int i = 1;中變數i被賦值幾次? 首先,我們來弄清楚這樣一個問題:靜態變數在什麼時候被載入?     靜態變數的宣告與初

java的強制型別轉換 int轉為byte

Java中的基本型別 java中所有的基本數值型別都有正負號,所以不要去尋找無符號的數值型別。 基本型別 大小 最小值 最大值 包裝器型別 boolea

java進位制的轉換,Byte16進位制的轉換

字串轉換成十六進位制字串方法1: /** * 字串轉換成十六進位制字串 */ public static String str2HexStr(String str) { char[] chars = "0123456789ABCDEF".toChar

Java基本資料型別對應的包裝類和引用資料型別

基本資料型別變數儲存的是值,引用型別儲存的是物件的引用(物件的地址)。 基本資料型別不具有物件的特性,當有些地方必須要使用物件的時候,例如集合類(List,Set等),基本資料型別就不能使用了,所以Java提供了包裝類。基本資料型別可以進行加減乘除等運算,而包裝類提供了很多

java的強制型別轉換

資料型別的轉換,分為自動轉換和強制轉換。自動轉換是程式在執行過程中 “ 悄然 ” 進行的轉換,不需要使用者提前宣告,一般是從位數低的型別向位數高的型別轉換;強制型別轉換則必須在程式碼中宣告,轉換順序不受限制。 自動資料型別轉換 自動轉換按從低到高的順序轉換。不同型別資