亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解決java數(shù)值范圍以及float與double精度丟失的問(wèn)題

 更新時(shí)間:2017年06月26日 08:47:36   投稿:jingxian  
下面小編就為大家?guī)?lái)一篇解決java數(shù)值范圍以及float與double精度丟失的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

1.java中int,float,long,double取值范圍

public class TestOutOfBound { 
public static void main(String[] args) { 
 
System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //內(nèi)存溢出 
System.out.println(Integer.MAX_VALUE); //2的31次方-1,10個(gè)數(shù)位,正的20億左右,用在錢(qián)上面不一定夠 
System.out.println(Integer.MIN_VALUE); //負(fù)的2的31次方 
System.out.println(Long.MAX_VALUE); //2的64次方-1,19個(gè)數(shù)位,很大了,可放心用在錢(qián)上面 
System.out.println(Long.MIN_VALUE); //負(fù)的2的64次方 
System.out.println(Float.MAX_VALUE); //2的128次方-1,38個(gè)數(shù)位,比long多了一倍,這個(gè)主要用來(lái)做簡(jiǎn)單數(shù)學(xué)精確運(yùn)算使用 
System.out.println(Float.MIN_VALUE); //2的-149次方 
System.out.println(Double.MAX_VALUE); //2的1024次方-1,308個(gè)數(shù)位,是float數(shù)位的10倍,主要用來(lái)做復(fù)雜運(yùn)算和天文運(yùn)算 
System.out.println(Double.MIN_VALUE); //2的-1074次方 
 
} 
} 

2.float與double精度丟失問(wèn)題

例子:

舉例:double result = 1.0 - 0.9; 
 
這個(gè)結(jié)果不用說(shuō)了吧,都知道了,0.09999999999999998

為什么會(huì)出現(xiàn)這個(gè)問(wèn)題呢,就這是java和其它計(jì)算機(jī)語(yǔ)言都會(huì)出現(xiàn)的問(wèn)題,下面我們分析一下為什么會(huì)出現(xiàn)這個(gè)問(wèn)題:

float和double類(lèi)型主要是為了科學(xué)計(jì)算和工程計(jì)算而設(shè)計(jì)的。他們執(zhí)行二進(jìn)制浮點(diǎn)運(yùn)算,這是為了在廣泛的數(shù)字范圍上提供較為精確的快速近似計(jì)算而精心設(shè)計(jì)的。然而,它們并沒(méi)有提供完全精確的結(jié)果,所以我們不應(yīng)該用于精確計(jì)算的場(chǎng)合。float和double類(lèi)型尤其不適合用于貨幣運(yùn)算,因?yàn)橐屢粋€(gè)float或double精確的表示0.1或者10的任何其他負(fù)數(shù)次方值是不可能的(其實(shí)道理很簡(jiǎn)單,十進(jìn)制系統(tǒng)中能不能準(zhǔn)確表示出1/3呢?同樣二進(jìn)制系統(tǒng)也無(wú)法準(zhǔn)確表示1/10)。

浮點(diǎn)運(yùn)算很少是精確的,只要是超過(guò)精度能表示的范圍就會(huì)產(chǎn)生誤差。往往產(chǎn)生誤差不是因?yàn)閿?shù)的大小,而是因?yàn)閿?shù)的精度。因此,產(chǎn)生的結(jié)果接近但不等于想要的結(jié)果。尤其在使用 float 和 double 作精確運(yùn)算的時(shí)候要特別小心。

現(xiàn)在我們就詳細(xì)剖析一下浮點(diǎn)型運(yùn)算為什么會(huì)造成精度丟失?

首先我們要搞清楚下面兩個(gè)問(wèn)題: 
 
  (1) 十進(jìn)制整數(shù)如何轉(zhuǎn)化為二進(jìn)制數(shù) 
 
     算法很簡(jiǎn)單。舉個(gè)例子,11表示成二進(jìn)制數(shù): 
 
          11/2=5 余  1 
 
           5/2=2  余  1 
 
           2/2=1  余  0 
 
           1/2=0  余  1 
 
            0結(jié)束     11二進(jìn)制表示為(從下往上):1011 
 
    這里提一點(diǎn):只要遇到除以后的結(jié)果為0了就結(jié)束了,大家想一想,所有的整數(shù)除以2是不是一定能夠最終得到0。換句話說(shuō),所有的整數(shù)轉(zhuǎn)變?yōu)槎M(jìn)制數(shù)的算法會(huì)不會(huì)無(wú)限循環(huán)下去呢?絕對(duì)不會(huì),整數(shù)永遠(yuǎn)可以用二進(jìn)制精確表示 ,但小數(shù)就不一定了。 
 
  (2) 十進(jìn)制小數(shù)如何轉(zhuǎn)化為二進(jìn)制數(shù) 
 
     算法是乘以2直到?jīng)]有了小數(shù)為止。舉個(gè)例子,0.9表示成二進(jìn)制數(shù) 
 
          0.9*2=1.8  取整數(shù)部分 1 
 
          0.8(1.8的小數(shù)部分)*2=1.6  取整數(shù)部分 1 
 
          0.6*2=1.2  取整數(shù)部分 1 
 
          0.2*2=0.4  取整數(shù)部分 0 
 
          0.4*2=0.8  取整數(shù)部分 0 
 
          0.8*2=1.6 取整數(shù)部分 1 
 
          0.6*2=1.2  取整數(shù)部分 0 
 
              .........   0.9二進(jìn)制表示為(從上往下): 1100100100100...... 
 
     注意:上面的計(jì)算過(guò)程循環(huán)了,也就是說(shuō)*2永遠(yuǎn)不可能消滅小數(shù)部分,這樣算法將無(wú)限下去。很顯然,小數(shù)的二進(jìn)制表示有時(shí)是不可能精確的 。其實(shí)道理很簡(jiǎn)單,十進(jìn)制系統(tǒng)中能不能準(zhǔn)確表示出1/3呢?同樣二進(jìn)制系統(tǒng)也無(wú)法準(zhǔn)確表示1/10。這也就解釋了為什么浮點(diǎn)型減法出現(xiàn)了"減不盡"的精度丟失問(wèn)題。

3.解決方法一:

如果不介意自己記錄十進(jìn)制的小數(shù)點(diǎn),而且數(shù)值不大,那么可以使用long ,int等基本類(lèi)型,具體用int還是long要看涉及的數(shù)值范圍大小,缺點(diǎn)是要自己處理十進(jìn)制小數(shù)點(diǎn),最明顯的做法就是處理貨幣使用分來(lái)計(jì)算,而不用元(只涉及加減)。

如:

int resultInt = 10 - 9;  
double result = (double) resultInt / 100;//最終時(shí)候自己控制小數(shù)點(diǎn)  

4.解決方法二:

使用BigDecmal,而且需要在構(gòu)造參數(shù)使用String類(lèi)型。

在《Effective Java》這本書(shū)中就給出了一個(gè)解決方法。該書(shū)中也指出,float和double只能用來(lái)做科學(xué)計(jì)算或者是工程計(jì)算,在商業(yè)計(jì)算等精確計(jì)算中,我們要用java.math.BigDecimal。

BigDecimal類(lèi)一個(gè)有4個(gè)方法,我們只關(guān)心對(duì)我們解決浮點(diǎn)型數(shù)據(jù)進(jìn)行精確計(jì)算有用的方法,即

BigDecimal(double value) // 將double型數(shù)據(jù)轉(zhuǎn)換成BigDecimal型數(shù)據(jù)

思路很簡(jiǎn)單,我們先通過(guò)BigDecimal(double value)方法,將double型數(shù)據(jù)轉(zhuǎn)換成BigDecimal數(shù)據(jù),然后就可以正常進(jìn)行精確計(jì)算了。等計(jì)算完畢后,我們可以對(duì)結(jié)果做一些處理,比如 對(duì)除不盡的結(jié)果可以進(jìn)行四舍五入。最后,再把結(jié)果由BigDecimal型數(shù)據(jù)轉(zhuǎn)換回double型數(shù)據(jù)。

這個(gè)思路很正確,但是如果你仔細(xì)看看API里關(guān)于BigDecimal的詳細(xì)說(shuō)明,你就會(huì)知道,如果需要精確計(jì)算,我們不能直接用double,而非要用 String來(lái)構(gòu)造BigDecimal不可!所以,我們又開(kāi)始關(guān)心BigDecimal類(lèi)的另一個(gè)方法,即能夠幫助我們正確完成精確計(jì)算的 BigDecimal(String value)方法。
// BigDecimal(String value)能夠?qū)tring型數(shù)據(jù)轉(zhuǎn)換成BigDecimal型數(shù)據(jù)

那么問(wèn)題來(lái)了,想像一下吧,如果我們要做一個(gè)浮點(diǎn)型數(shù)據(jù)的加法運(yùn)算,需要先將兩個(gè)浮點(diǎn)數(shù)轉(zhuǎn)為String型數(shù)據(jù),然后用 BigDecimal(String value)構(gòu)造成BigDecimal,之后要在其中一個(gè)上調(diào)用add方法,傳入另一個(gè)作為參數(shù),然后把運(yùn)算的結(jié)果(BigDecimal)再轉(zhuǎn)換為浮 點(diǎn)數(shù)。如果每次做浮點(diǎn)型數(shù)據(jù)的計(jì)算都要如此,你能夠忍受這么煩瑣的過(guò)程嗎?至少我不能。所以最好的辦法,就是寫(xiě)一個(gè)類(lèi),在類(lèi)中完成這些繁瑣的轉(zhuǎn)換過(guò)程。這 樣,在我們需要進(jìn)行浮點(diǎn)型數(shù)據(jù)計(jì)算的時(shí)候,只要調(diào)用這個(gè)類(lèi)就可以了。網(wǎng)上已經(jīng)有高手為我們提供了一個(gè)工具類(lèi)Arith來(lái)完成這些轉(zhuǎn)換操作。它提供以下靜態(tài) 方法,可以完成浮點(diǎn)型數(shù)據(jù)的加減乘除運(yùn)算和對(duì)其結(jié)果進(jìn)行四舍五入的操作:

public static double add(double v1,double v2)

public static double sub(double v1,double v2)

public static double mul(double v1,double v2)

public static double div(double v1,double v2)

public static double div(double v1,double v2,int scale)

public static double round(double v,int scale)

下面會(huì)附上Arith的源代碼,大家只要把它編譯保存好,要進(jìn)行浮點(diǎn)數(shù)計(jì)算的時(shí)候,在你的源程序中導(dǎo)入Arith類(lèi)就可以使用以上靜態(tài)方法來(lái)進(jìn)行浮點(diǎn)數(shù)的精確計(jì)算了。

附錄:Arith源代碼

import java.math.BigDecimal; 
 
/** 
* 由于Java的簡(jiǎn)單類(lèi)型不能夠精確的對(duì)浮點(diǎn)數(shù)進(jìn)行運(yùn)算,這個(gè)工具類(lèi)提供精 
* 確的浮點(diǎn)數(shù)運(yùn)算,包括加減乘除和四舍五入。 
*/ 
 
public class Arith{ 
  //默認(rèn)除法運(yùn)算精度 
  private static final int DEF_DIV_SCALE = 10; 
  //這個(gè)類(lèi)不能實(shí)例化 
  private Arith(){ 
  } 
 
  /** 
   * 提供精確的加法運(yùn)算。 
   * @param v1 被加數(shù) 
   * @param v2 加數(shù) 
   * @return 兩個(gè)參數(shù)的和 
   */ 
  public static double add(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.add(b2).doubleValue(); 
  } 
  /** 
   * 提供精確的減法運(yùn)算。 
   * @param v1 被減數(shù) 
   * @param v2 減數(shù) 
   * @return 兩個(gè)參數(shù)的差 
   */ 
  public static double sub(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.subtract(b2).doubleValue(); 
  } 
  /** 
   * 提供精確的乘法運(yùn)算。 
   * @param v1 被乘數(shù) 
   * @param v2 乘數(shù) 
   * @return 兩個(gè)參數(shù)的積 
   */ 
  public static double mul(double v1,double v2){ 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.multiply(b2).doubleValue(); 
  } 
 
  /** 
   * 提供(相對(duì))精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時(shí),精確到 
   * 小數(shù)點(diǎn)以后10位,以后的數(shù)字四舍五入。 
   * @param v1 被除數(shù) 
   * @param v2 除數(shù) 
   * @return 兩個(gè)參數(shù)的商 
   */ 
  public static double div(double v1,double v2){ 
    return div(v1,v2,DEF_DIV_SCALE); 
  } 
 
  /** 
   * 提供(相對(duì))精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時(shí),由scale參數(shù)指 
   * 定精度,以后的數(shù)字四舍五入。 
   * @param v1 被除數(shù) 
   * @param v2 除數(shù) 
   * @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。 
   * @return 兩個(gè)參數(shù)的商 
   */ 
  public static double div(double v1,double v2,int scale){ 
    if(scale<0){ 
      throw new IllegalArgumentException( 
        "The scale must be a positive integer or zero"); 
    } 
    BigDecimal b1 = new BigDecimal(Double.toString(v1)); 
    BigDecimal b2 = new BigDecimal(Double.toString(v2)); 
    return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
  } 
 
  /** 
   * 提供精確的小數(shù)位四舍五入處理。 
   * @param v 需要四舍五入的數(shù)字 
   * @param scale 小數(shù)點(diǎn)后保留幾位 
   * @return 四舍五入后的結(jié)果 
   */ 
  public static double round(double v,int scale){ 
 
    if(scale<0){ 
      throw new IllegalArgumentException( 
        "The scale must be a positive integer or zero"); 
    } 
    BigDecimal b = new BigDecimal(Double.toString(v)); 
    BigDecimal one = new BigDecimal("1"); 
    return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
  } 
}; 

以上這篇解決java數(shù)值范圍以及float與double精度丟失的問(wèn)題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java編程實(shí)現(xiàn)非對(duì)稱(chēng)加密的方法詳解

    Java編程實(shí)現(xiàn)非對(duì)稱(chēng)加密的方法詳解

    這篇文章主要介紹了Java編程實(shí)現(xiàn)非對(duì)稱(chēng)加密的方法,簡(jiǎn)單講述了非對(duì)稱(chēng)加密的概念、原理,并結(jié)合實(shí)例形式分析了java實(shí)現(xiàn)DH加密解密、RSA加密解密、ElGamal加密等具體操作技巧,需要的朋友可以參考下
    2017-08-08
  • Spring成員對(duì)象注入的三種方式詳解

    Spring成員對(duì)象注入的三種方式詳解

    這篇文章主要為大家詳細(xì)介紹了Spring成員對(duì)象注入的三種方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • 代碼分析Spring MVC的工作原理

    代碼分析Spring MVC的工作原理

    在本篇文章里小編給大家整理了關(guān)于Spring MVC的工作原理的相關(guān)知識(shí)點(diǎn)以及實(shí)例代碼內(nèi)容,需要的朋友們可以參考下。
    2019-06-06
  • 在lambda的foreach遍歷中break退出操作(lambda foreach break)

    在lambda的foreach遍歷中break退出操作(lambda foreach break)

    這篇文章主要介紹了在lambda的foreach遍歷中break退出操作(lambda foreach break),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • SpringBoot自動(dòng)裝配之@Import深入講解

    SpringBoot自動(dòng)裝配之@Import深入講解

    由于最近的項(xiàng)目需求,需要在把配置類(lèi)導(dǎo)入到容器中,通過(guò)查詢,使用@Import注解就能實(shí)現(xiàn)這個(gè)功能,@Import注解能夠幫我們吧普通配置類(lèi)(定義為Bean的類(lèi))導(dǎo)入到IOC容器中
    2023-01-01
  • Spring?MVC?URL地址映射的示例代碼

    Spring?MVC?URL地址映射的示例代碼

    @RequestMapping是一個(gè)用來(lái)處理請(qǐng)求地址映射的注解,可用于類(lèi)或方法上。用于類(lèi)上,表示類(lèi)中的所有響應(yīng)請(qǐng)求的方法都是以該地址作為父路徑。,這篇文章主要介紹了Spring?MVC?URL地址映射,需要的朋友可以參考下
    2022-07-07
  • SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解

    SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解

    這篇文章主要介紹了SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java生成隨機(jī)數(shù)的方法

    java生成隨機(jī)數(shù)的方法

    這篇文章主要介紹了java生成隨機(jī)數(shù)的方法,涉及java隨機(jī)數(shù)及字符串操作的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • SpringBoot動(dòng)態(tài)更新yml文件

    SpringBoot動(dòng)態(tài)更新yml文件

    在系統(tǒng)運(yùn)行過(guò)程中,可能由于一些配置項(xiàng)的簡(jiǎn)單變動(dòng)需要重新打包啟停項(xiàng)目,這對(duì)于在運(yùn)行中的項(xiàng)目會(huì)造成數(shù)據(jù)丟失,客戶操作無(wú)響應(yīng)等情況發(fā)生,針對(duì)這類(lèi)情況對(duì)開(kāi)發(fā)框架進(jìn)行升級(jí)提供yml文件實(shí)時(shí)修改更新功能,這篇文章主要介紹了SpringBoot動(dòng)態(tài)更新yml文件
    2023-01-01
  • Java8中用foreach循環(huán)獲取對(duì)象的index下標(biāo)詳解

    Java8中用foreach循環(huán)獲取對(duì)象的index下標(biāo)詳解

    這篇文章主要給大家介紹了關(guān)于Java8中用foreach循環(huán)獲取對(duì)象的index下標(biāo)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評(píng)論