<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      shuijibaobao

      導(dǎo)航

       

      1. 概述

      BigDecimal是Java在java.math包中提供的線程安全的API類。BigDecimal是Java中用于表示任意精度數(shù)字的類,它可以表示無限長度的小數(shù),BigDecimal 通常支持任意位數(shù)的小數(shù)部分,用來對超過16位有效位的數(shù)進(jìn)行精確的運算。雙精度浮點型變量double可以處理16位有效數(shù),但在實際應(yīng)用中,可能需要對更大或者更小的數(shù)進(jìn)行運算和處理。一般情況下,對于那些不需要準(zhǔn)確計算精度的數(shù)字,我們可以直接使用Float和Double處理,但是Double.valueOf(String) 和Float.valueOf(String)會丟失精度。所以開發(fā)中,如果我們需要精確計算的結(jié)果,則必須使用BigDecimal類來操作。

      ? BigDecimal所創(chuàng)建的是對象,故我們不能使用傳統(tǒng)的+、-、*、/等算術(shù)運算符直接對其對象進(jìn)行數(shù)學(xué)運算,而必須調(diào)用其相對應(yīng)的方法。方法中的參數(shù)也必須是BigDecimal的對象。構(gòu)造器是類的特殊方法,專門用來創(chuàng)建對象,特別是帶有參數(shù)的對象。

       2. 常用構(gòu)造方法

       3. BigDecimal常用方法

      注意:BigDecimal進(jìn)行運算時必須要保證對象本身不能是null,否則就會拋空指針異常

       代碼示例:

      import java.math.BigDecimal;
      
      public class Test {
          public static void main(String[] args){
              BigDecimal b1 = new BigDecimal("1");
              BigDecimal b2 = new BigDecimal("2");
              BigDecimal b3 = new BigDecimal("4");
              System.out.println("相加:"+b1.add(b2));
              System.out.println("相減:"+b1.subtract(b2));
              System.out.println("相乘:"+b2.multiply(b3));
              System.out.println("相除:"+b2.divide(b3));
          }
      }

      4. 進(jìn)階

      4.1、BigDecimal的八種舍入模式

      BigDecimal.setScale()方法用于格式化小數(shù)點
      setScale(1)表示保留一位小數(shù),默認(rèn)用四舍五入方式
      setScale(1,BigDecimal.ROUND_DOWN)直接刪除多余的小數(shù)位,如2.35會變成2.3
      setScale(1,BigDecimal.ROUND_UP)進(jìn)位處理,2.35變成2.4
      setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35變成2.4
      setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入,2.35變成2.3,如果是5則向下舍
      setScaler(1,BigDecimal.ROUND_CEILING)接近正無窮大的舍入
      setScaler(1,BigDecimal.ROUND_FLOOR)接近負(fù)無窮大的舍入,數(shù)字>0和ROUND_UP作用一樣,數(shù)字<0和ROUND_DOWN作用一樣
      setScaler(1,BigDecimal.ROUND_HALF_EVEN)向最接近的數(shù)字舍入,如果與兩個相鄰數(shù)字的距離相等,則向相鄰的偶數(shù)舍入。

      1、ROUND_UP,向遠(yuǎn)離0的方向舍入,在丟棄非零部分之前始終增加數(shù)字(始終對非零舍棄部分前面的數(shù)字加1)。
      注意,此舍入模式始終不會減少計算值的大小。
      eg: 保留1位小數(shù) 1.60->1.6 1.61->1.7 1.66->1.7 , -1.62->-1.7

      2、ROUND_DOWN,向接近0的方向舍入,在丟棄某部分之前,始終不增加數(shù)據(jù)(即,截斷),該方式是只減不加。
      eg: 保留1位小數(shù) 1.60->1.6 1.61->1.6 1.66->1.6 , -1.62->-1.6

      3、ROUND_CEILING,向正無窮方向舍入,如果數(shù)值為正,舍入方式與ROUND_UP一致,如果為負(fù),舍入方式與ROUND_DOWN一致,該模式始終不會減少計算數(shù)值。
      eg: 保留1位小數(shù) 1.60->1.6 1.61->1.7 1.66->1.7 , -1.62->-1.6

      4、ROUND_FLOOR,向負(fù)無窮方向舍入,如果數(shù)值為正,舍入行為與 ROUND_DOWN 相同;如果為負(fù),則舍入行為與 ROUND_UP 相同。該模式始終不會增加計算數(shù)值。
      eg: 保留1位小數(shù) 1.60->1.6 1.61->1.6 1.66->1.6 , -1.62->-1.7

      5、ROUND_HALF_UP,向“最接近的”數(shù)字舍入,也就是四舍五入。
      eg: 保留1位小數(shù) 1.61->1.6 1.65->1.7 1.66->1.7 , -1.62->-1.6

      6、ROUND_HALF_DOWN,向“最接近的”數(shù)字舍入,如果與兩個相鄰數(shù)字的距離相等,則為上舍入的舍入模式,也就是五舍六入。
      eg: 保留1位小數(shù) 1.61->1.6 1.65->1.6 1.66->1.7 , -1.62->-1.6

       

      7、ROUND_HALF_EVEN,向“最接近的”數(shù)字舍入,如果與兩個相鄰數(shù)字的距離相等,則向相鄰的偶數(shù)舍入。如果舍棄部分左邊的數(shù)字為奇數(shù),則舍入行為與 ROUND_HALF_UP 相同;如果為偶數(shù),則舍入行為與 ROUND_HALF_DOWN 相同。
      注意,在重復(fù)進(jìn)行一系列計算時,此舍入模式可以將累加錯誤減到最小。
      此舍入模式也稱為“銀行家舍入法”,主要在美國使用。四舍六入,五分兩種情況。如果前一位為奇數(shù),則入位,否則舍去。以下例子為保留小數(shù)點1位,那么這種舍入方式下的結(jié)果。
      eg. 1.15->1.2, 1.25->1.2

      8、ROUND_UNNECESSARY,計算結(jié)果是精確的,不需要舍入模式。如果對獲得精確結(jié)果的操作指定此舍入模式,則拋出ArithmeticException。

      BigDecimal b = new BigDecimal("1.6666");
      System.out.println("result b:" + b.setScale(2, BigDecimal.ROUND_HALF_UP)); // 1.67
      System.out.println("result b:" + b.setScale(2)); // 精度錯誤

      result b:1.67
      Exception in thread "main" java.lang.ArithmeticException: Rounding necessar

      原因分析:

      setScale方法默認(rèn)使用的roundingMode是ROUND_UNNECESSARY,不需要使用舍入模式,設(shè)置精度2位,但是小數(shù)點后有4位肯定會拋異常。

      4.2、BigDecimal格式化、小數(shù)點轉(zhuǎn)換

      BigDecimal可以與DecimalFormat結(jié)合使用,從而對金額格式化,如小數(shù)點后面統(tǒng)一保留兩位,不夠兩位的補零,多余兩位的舍入。

      import java.math.BigDecimal;
      import java.text.DecimalFormat;
      
      public class Test {
          public static void main(String[] s){
              System.out.println(formatToNumber(new BigDecimal("12333.435")));
              System.out.println(formatToNumber(new BigDecimal(0)));
              System.out.println(formatToNumber(new BigDecimal("0.00")));
              System.out.println(formatToNumber(new BigDecimal("0.001")));
              System.out.println(formatToNumber(new BigDecimal("0.006")));
              System.out.println(formatToNumber(new BigDecimal("0.206")));
              System.out.println(formatToNumber(new BigDecimal("1.22")));
          }
          /**
           * @desc
           * @param obj 傳入的小數(shù)
           * @return
           */
          public static String formatToNumber(BigDecimal obj) {
              // DecimalFormat默認(rèn)使用的是進(jìn)位方式是RoundingMode.HALF_EVEN,此舍入模式也稱為“銀行家算法”,主要在美國使用。
              //銀行家算法:四舍六入五考慮,五后非零就進(jìn)一,五后為零看奇偶,五前為偶應(yīng)舍去,五前為奇要進(jìn)一
              DecimalFormat df = new DecimalFormat("###,##0.00"); 
              return df.format(obj);
          }
      }

      //執(zhí)行結(jié)果
      12,333.44
      0.00
      0.00
      0.00
      0.01
      0.21
      1.22

       

      需注意:

          DecimalFormat的默認(rèn)進(jìn)位方式不是四舍五入,所以當(dāng)小數(shù)點后面需要舍去的時候,肯能跟預(yù)想的不一樣,具體可參考《關(guān)于DecimalFormat的取舍問題,DecimalFormat四舍五入的坑》
          new DecimalFormat(“###,##0.00”)小數(shù)點前面需要有個0,這樣0-1之間的數(shù)字才會正常格式化;若##0.00的小數(shù)點前面沒有0,則0-1之間的數(shù)字會被丟失掉小數(shù)點前的0,代碼如下:

      import java.math.BigDecimal;
      import java.text.DecimalFormat;
      
      public class Test {
          public static void main(String[] s){
              System.out.println(formatToNumber(new BigDecimal("12333.435")));
              System.out.println(formatToNumber(new BigDecimal(0)));
              System.out.println(formatToNumber(new BigDecimal("0.00")));
              System.out.println(formatToNumber(new BigDecimal("0.001")));
              System.out.println(formatToNumber(new BigDecimal("0.006")));
              System.out.println(formatToNumber(new BigDecimal("0.206")));
              System.out.println(formatToNumber(new BigDecimal("1.22")));
          }
          /**
           * @desc
           * @param obj 傳入的小數(shù)
           * @return
           */
          public static String formatToNumber(BigDecimal obj) {
              // DecimalFormat默認(rèn)使用的是進(jìn)位方式是RoundingMode.HALF_EVEN,此舍入模式也稱為“銀行家算法”,主要在美國使用。
              //銀行家算法:四舍六入五考慮,五后非零就進(jìn)一,五后為零看奇偶,五前為偶應(yīng)舍去,五前為奇要進(jìn)一
              DecimalFormat df = new DecimalFormat("###,##.00");
              return df.format(obj);
          }
      }
      1,23,33.44
      .00
      .00
      .00
      .01
      .21
      1.22

       

      4.3、貨幣格式化與百分比格式化

          經(jīng)常能看到金額用¥120.00表示,利率用0.8%表示,這里擴(kuò)展一下BigDecimal的貨幣格式化與百分比格式化

          NumberFormat類的format()方法可以使用BigDecimal對象作為其參數(shù),可以利用BigDecimal對超出16位有效數(shù)字的貨幣值,百分值,以及一般數(shù)值進(jìn)行格式化控制。

          NumberFormat對象:
          getCompactNumberInstance();返回FORMAT帶有"SHORT"格式樣式的默認(rèn)語言環(huán)境 的緊湊數(shù)字格式 。
          getCurrencyInstance?(Locale inLocale);返回指定語言環(huán)境的貨幣格式。若是不指定參數(shù),則以默認(rèn)語言為參數(shù)。
          getInstance?(Locale inLocale);返回指定語言環(huán)境的通用數(shù)字格式。若是不指定參數(shù),則以默認(rèn)語言為參數(shù)。
          getPercentInstance?(Locale inLocale);返回指定語言環(huán)境的百分比格式。若是不指定參數(shù),則以默認(rèn)語言為參數(shù)。

      import java.math.BigDecimal;
      import java.text.NumberFormat;
      
      public class Test {
          public static void main(String[] args){
              NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立貨幣格式化引用
              NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
              percent.setMinimumFractionDigits(2);//設(shè)置數(shù)的小數(shù)部分所允許的最小位數(shù)(如果不足后面補0)
              percent.setMaximumFractionDigits(3);//設(shè)置數(shù)的小數(shù)部分所允許的最大位數(shù)(如果超過會四舍五入)
      
              BigDecimal amount = new BigDecimal("250600.42"); //金額
              BigDecimal interestRate = new BigDecimal("0.0004"); //利率
              BigDecimal interest = amount .multiply(interestRate); //相乘
      
              System.out.println("金額: " + currency.format(loanAmount));
              System.out.println("利率: " + percent.format(interestRate));
              System.out.println("利息: " + currency.format(interest));
          }
      }
      金額: ¥250,600.42
      利率: 0.04%
      利息: ¥100.24

       

      NumberFormat提供了多種貨幣格式的引用,如¥(人民幣),$(美元、英元)等等

      五、BigDecimal常見問題

      5.1、踩坑一:創(chuàng)建 BigDecimal精度丟失的坑

      在BigDecimal 中提供了多種創(chuàng)建方式,可以通過new 直接創(chuàng)建,也可以通過 BigDecimal#valueOf 創(chuàng)建。這兩種方式使用不當(dāng),也會導(dǎo)致精度問題。如下:

      public static void main(String[] args) throws Exception {
         BigDecimal b1= new BigDecimal(0.1);
         System.out.println(b1);
         BigDecimal b2= BigDecimal.valueOf(0.1);
         System.out.println(b2);
         BigDecimal b3= BigDecimal.valueOf(0.111111111111111111111111111234);
         System.out.println(b3);
      }
      0.1000000000000000055511151231257827021181583404541015625
      0.1
      0.1111111111111111

      上面示例中兩個方法都傳入了double類型的參數(shù)0.1但是 b1 還是出現(xiàn)了精度的問題。造成這種問題的原因是 0.1 這個數(shù)字計算機是無法精確表示的,送給 BigDecimal 的時候就已經(jīng)丟精度了,而 BigDecimal#valueOf 的實現(xiàn)卻完全不同。如下源碼所示,BigDecimal#valueOf 中是把浮點數(shù)轉(zhuǎn)換成了字符串來構(gòu)造的BigDecimal,因此避免了問題。

      public static BigDecimal valueOf(double val) {
         return new BigDecimal(Double.toString(val));
      }

      結(jié)論:

          第一,在使用BigDecimal構(gòu)造函數(shù)時,盡量傳遞字符串而非浮點類型;
          第二,如果無法滿足第一條,則可采用BigDecimal#valueOf方法來構(gòu)造初始化值。但是valueOf受double類型精度影響,當(dāng)傳入?yún)?shù)小數(shù)點后的位數(shù)超過double允許的16位精度還是可能會出現(xiàn)問題的

      5.2、踩坑二:等值比較的坑

      一般在比較兩個值是否相等時,都是用equals 方法,但是,在BigDecimal 中使用equals可能會導(dǎo)致結(jié)果錯誤,BigDecimal 中提供了 compareTo 方法,在很多時候需要使用compareTo 比較兩個值。如下所示:

      public static void main(String[] args){
          BigDecimal b1 = new BigDecimal("1.0");
          BigDecimal b2 = new BigDecimal("1.00");
          System.out.println(b1.equals(b2));
          System.out.println(b1.compareTo(b2));
      }
      false
      0

      出現(xiàn)此種結(jié)果的原因是,equals不僅比較了值是否相等,還比較了精度是否相同。示例中,由于兩個值的精度不同,所有結(jié)果也就不相同。而 compareTo 是只比較值的大小。返回的值為-1(小于),0(等于),1(大于)。

      結(jié)論

      • 如果比較兩個BigDecimal值的大小,采用其實現(xiàn)的compareTo方法;
      • 如果嚴(yán)格限制精度的比較,那么則可考慮使用equals方法。

      5.3、踩坑三:無限精度的坑

      BigDecimal 并不代表無限精度,當(dāng)在兩個數(shù)除不盡的時候,就會出現(xiàn)無限精度的坑,如下所示:

       public static void main(String[] args){
         BigDecimal b1 = new BigDecimal("1.0");
          BigDecimal b2 = new BigDecimal("3.0");
          b1.divide(b2);
      }
      Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
          at java.math.BigDecimal.divide(BigDecimal.java:1693)
          at com.demo.controller.Test.main(Test.java:29)

      大致意思就是,如果在除法(divide)運算過程中,如果商是一個無限小數(shù)(如 0.333…),而操作的結(jié)果預(yù)期是一個精確的數(shù)字,那么將會拋出ArithmeticException異常。

      此種情況,只需要在使用 divide方法時指定結(jié)果的精度即可:

      public static void main(String[] args){
         BigDecimal b1 = new BigDecimal("1.0");
         BigDecimal b2 = new BigDecimal("3.0");
         System.out.println(b1.divide(b2,2, RoundingMode.HALF_UP));//0.33
      }

      結(jié)論:

      • 在使用BigDecimal進(jìn)行(所有)運算時,盡量指定精度和舍入模式。

       

      5.4、踩坑四:BigDecimal三種字符串輸出的坑

      在BigDecimal 轉(zhuǎn)換成字符串時,有可能輸出非你預(yù)期的結(jié)果。如下所示:

      public static void main(String[] args){
         BigDecimal bg = new BigDecimal("1E11");
          System.out.println(bg.toString()); // 1E+11
          System.out.println(bg.toPlainString()); // 100000000000
          System.out.println(bg.toEngineeringString()); // 100E+9
      }
      1E+11
      100000000000
      100E+9

      可以看到三種方式輸出的結(jié)果可能都不相同,可能這個并不是預(yù)期的結(jié)果 ,BigDecimal 有三個方法可以轉(zhuǎn)為相應(yīng)的字符串類型,切記不要用錯:

      以下內(nèi)容介紹java.math.BigDecimal下的三個toString方法的區(qū)別及用法

      toPlainString() : 不使用任何指數(shù)。
      toString() :有必要時使用科學(xué)計數(shù)法。
      toEngineeringString():有必要時使用工程計數(shù)法。 工程記數(shù)法是一種工程計算中經(jīng)常使用的記錄數(shù)字的方法,與科學(xué)技術(shù)法類似,但要求10的冪必須是3的倍數(shù)

      5.5、踩坑五:使用BigDecimal進(jìn)行計算時參數(shù)不能為NULL

      在使用BigDecimal類型進(jìn)行計算時,進(jìn)行加、減、乘、除、比較大小時,一定要保證參與計算的兩個值不能為空,否則會拋出java.lang.NullPointerException異常。

      BigDecimal b1 = new BigDecimal("1");
      BigDecimal b2 = null;
      System.out.println("相加:"+b2.add(b1));
      
      Exception in thread "main" java.lang.NullPointerException
          at com.demo.controller.Test.main(Test.java:14)

      5.6、踩坑六:使用BigDecimal進(jìn)行除法計算時被除數(shù)不能為0

      代碼示例:

      BigDecimal b1 = new BigDecimal("1");
      BigDecimal b2 = new BigDecimal("0");
      System.out.println(b1.divide(b2));
      
      Exception in thread "main" java.lang.ArithmeticException: Division by zero

      踩坑七:執(zhí)行順序不能調(diào)換(乘法交換律失效)

      乘法滿足交換律是一個常識,但是在計算機的世界里,會出現(xiàn)不滿足乘法交換律的情況;

      代碼示例:

      BigDecimal b1 = BigDecimal.valueOf(1.0);
      BigDecimal b2 = BigDecimal.valueOf(3.0);
      BigDecimal b3 = BigDecimal.valueOf(3.0);
      System.out.println(b1.divide(b2, 2, RoundingMode.HALF_UP).multiply(b3)); // 0.990
      System.out.println(b1.multiply(b3).divide(b2, 2, RoundingMode.HALF_UP)); // 1.00

      執(zhí)行順序交換后,產(chǎn)生的結(jié)果可能不同,會導(dǎo)致一定的問題,使用順序建議先乘后除。

       

      posted on 2024-07-23 13:58  水吉z  閱讀(863)  評論(0)    收藏  舉報
       
      主站蜘蛛池模板: 熟女女同亚洲女同中文字幕| 成人无码精品免费视频在线观看 | 一级做a爰片在线播放| 一本色道久久东京热| 欧美日本激情| 国产亚洲一区二区三区av| 国产91色综合久久高清| 国产片AV国语在线观看手机版| 农村老熟妇乱子伦视频| 三人成全免费观看电视剧高清| 国产熟睡乱子伦视频在线播放| 国产成人精品亚洲午夜| 国产成人精品亚洲日本片| 国产免费福利网站| 在线中文字幕国产一区| 九九久久人妻一区精品色| 亚洲一区二区三区四区三级视频| 亚洲人成网站在线观看播放不卡| 欧美亚洲另类自拍偷在线拍| 素人视频亚洲十一十二区| 久久国产精品老人性| 午夜精品一区二区三区成人| 少妇高清一区二区免费看| 国产精品自在线拍国产手机版 | 亚洲男人综合久久综合天堂| 猫咪www免费人成网站| 日本高清一区免费中文视频| 久久99九九精品久久久久蜜桃| 久久综合国产色美利坚| 久久精品一区二区日韩av| 久久成人影院精品777| 日韩国产中文字幕精品| 精品国际久久久久999波多野| 狠狠色综合久久狠狠色综合 | 乱60一70归性欧老妇| 亚洲精品中文字幕尤物综合| 日本无人区一区二区三区| 性欧美VIDEOFREE高清大喷水| av色国产色拍| 日本一区二区三区在线播放| 欧美三级不卡在线观线看高清|