最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何使用BigDecimal實(shí)現(xiàn)Java開發(fā)商業(yè)計(jì)算

 更新時(shí)間:2020年09月21日 10:03:26   作者:碼農(nóng)小胖哥  
這篇文章主要介紹了如何使用BigDecimal實(shí)現(xiàn)Java開發(fā)商業(yè)計(jì)算,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

今天群里一個(gè)初級開發(fā)者問為什么測試人員測出來他寫的價(jià)格計(jì)算模塊有計(jì)算偏差的問題,他檢查了半天也沒找出問題。這里小胖哥要提醒你,商業(yè)計(jì)算請務(wù)必使用BigDecimal,浮點(diǎn)做商業(yè)運(yùn)算是不精確的。因?yàn)橛?jì)算機(jī)無法使用二進(jìn)制小數(shù)來精確描述我們程序中的十進(jìn)制小數(shù)?!禘ffective Java》在第48條也推薦“使用BigDecimal來做精確運(yùn)算”。今天我們就來總結(jié)歸納其相關(guān)的知識點(diǎn)。

BigDecimal

BigDecimal表示不可變的任意精度帶符號十進(jìn)制數(shù)。它由兩部分組成:

  • intVal - 未校正精度的整數(shù),類型為BigInteger
  • Scale - 一個(gè)32位整數(shù),表示小數(shù)點(diǎn)右邊的位數(shù)

例如,BigDecimal 3.14的未校正值為314,縮放為2。我們使用BigDecimal進(jìn)行高精度算術(shù)運(yùn)算。我們還將它用于需要控制比例和舍入行為的計(jì)算。如果你的計(jì)算是商業(yè)計(jì)算請務(wù)必使用計(jì)算精確的BigDecimal 。

構(gòu)造BigDecimal實(shí)例

我們可以從String,character 數(shù)組,int,long和BigInteger創(chuàng)建一個(gè)BigDecimal對象:

@Test
public void theValueMatches() {
  BigDecimal bdFromString = new BigDecimal("0.12");
  BigDecimal bdFromCharArray = new BigDecimal(new char[]{'3', '.', '1', '4', '1', '5'});
  BigDecimal bdlFromInt = new BigDecimal(42);
  BigDecimal bdFromLong = new BigDecimal(123412345678901L);
  BigInteger bigInteger = BigInteger.probablePrime(100, new Random());
  BigDecimal bdFromBigInteger = new BigDecimal(bigInteger);
  assertEquals("0.12", bdFromString.toString());
  assertEquals("3.1415", bdFromCharArray.toString());
  assertEquals("42", bdlFromInt.toString());
  assertEquals("123412345678901", bdFromLong.toString());
  assertEquals(bigInteger.toString(), bdFromBigInteger.toString());
}

我們還可以從double創(chuàng)建BigDecimal:

@Test
public void whenBigDecimalCreatedFromDouble_thenValueMayNotMatch() {
  BigDecimal bdFromDouble = new BigDecimal(0.1d);
  assertNotEquals("0.1", bdFromDouble.toString());
}

我們發(fā)現(xiàn)在這種情況下,結(jié)果與預(yù)期的結(jié)果不同(即0.1)。這是因?yàn)椋哼@個(gè)轉(zhuǎn)換結(jié)果是double的二進(jìn)制浮點(diǎn)值的精確十進(jìn)制表示,其值得結(jié)果不是我們可以預(yù)測的.我們應(yīng)該使用String構(gòu)造函數(shù)而不是double構(gòu)造函數(shù)。另外,我們可以使用valueOf靜態(tài)方法將double轉(zhuǎn)換為BigDecimal 或者直接使用其未校正數(shù)加小數(shù)位數(shù) :

@Test
public void whenBigDecimalCreatedUsingValueOf_thenValueMatches() {
    BigDecimal bdFromDouble = BigDecimal.valueOf(0.1d);
    BigDecimal bigFromLong=BigDecimal.valueOf(1,1);

    assertEquals("0.1", bdFromDouble.toString());
    assertEquals("0.1", bigFromLong.toString());
}

在轉(zhuǎn)換為BigDecimal之前,此方法將double轉(zhuǎn)換為其String表示形式。此外,它可以重用對象實(shí)例。因此,我們應(yīng)該優(yōu)先使用valueOf方法來構(gòu)造函數(shù)。

常用API

方法名 對應(yīng)方法相關(guān)用法解釋
abs() 絕對值,scale不變
add(BigDecimal augend) 加,scale為augend和原值scale的較大值
subtract(BigDecimal augend) 減,scale為augend和原值scale的較大值
multiply(BigDecimal multiplicand) 乘,scale為augend和原值scale的和
divide(BigDecimal divisor) 除,原值/divisor,如果不能除盡會拋出異常,scale與原值一致
divide(BigDecimal divisor, int roundingMode) 除,指定舍入方式,scale與原值一致
divide(BigDecimal divisor, int scale, int roundingMode) 除,指定舍入方式和scale
remainder(BigDecimal divisor) 取余,scale與原值一致
divideAndRemainder(BigDecimal divisor) 除法運(yùn)算后返回一個(gè)數(shù)組存放除盡和余數(shù) 如 23/3 返回 {7,2}
divideToIntegralValue(BigDecimal divisor) 除,只保留整數(shù)部分,但scale仍與原值一致
max(BigDecimal val) 較大值,返回原值與val中的較大值,與結(jié)果的scale一致
min(BigDecimal val) 較小值,與結(jié)果的scale一致
movePointLeft(int n) 小數(shù)點(diǎn)左移,scale為原值scale+n
movePointRight(int n) 小數(shù)點(diǎn)右移,scale為原值scale+n
negate() 取反,scale不變
pow(int n) 冪,原值^n,原值的n次冪
scaleByPowerOfTen(int n) 相當(dāng)于小數(shù)點(diǎn)右移n位,原值*10^n

BigDecimal操作

BigDecimal上的操作就像其他Number類(Integer,Long,Double等)一樣,BigDecimal提供算術(shù)和比較操作的操作。它還提供了縮放操作,舍入和格式轉(zhuǎn)換的操作。它不會使算術(shù)運(yùn)算符(+ - /*)或邏輯運(yùn)算符(> < | &) 過載。相反,我們使用BigDecimal相應(yīng)的方法 - 加,減,乘,除和比較。并且BigDecimal具有提取各種屬性的方法。

提取屬性

精度,小數(shù)位數(shù)和符號:

@Test
public void whenGettingAttributes_thenExpectedResult() {
  BigDecimal bd = new BigDecimal("-12345.6789");

  assertEquals(9, bd.precision());
  assertEquals(4, bd.scale());
  assertEquals(-1, bd.signum());
}

比較大小

我們使用compareTo方法比較兩個(gè)BigDecimal的值:

@Test
public void whenComparingBigDecimals_thenExpectedResult() {
  BigDecimal bd1 = new BigDecimal("1.0");
  BigDecimal bd2 = new BigDecimal("1.00");
  BigDecimal bd3 = new BigDecimal("2.0");

  assertTrue(bd1.compareTo(bd3) < 0);
  assertTrue(bd3.compareTo(bd1) > 0);
  assertTrue(bd1.compareTo(bd2) == 0);
  assertTrue(bd1.compareTo(bd3) <= 0);
  assertTrue(bd1.compareTo(bd2) >= 0);
  assertTrue(bd1.compareTo(bd3) != 0);
}

上面的方法在比較時(shí)忽略了小數(shù)位。如果你既要比較精度又要比較小數(shù)位數(shù)那么請使用equals方法:

@Test
public void whenEqualsCalled_thenSizeAndScaleMatched() {
  BigDecimal bd1 = new BigDecimal("1.0");
  BigDecimal bd2 = new BigDecimal("1.00");

  assertFalse(bd1.equals(bd2));
}

四則運(yùn)算

BigDecimal 提供了以下四則運(yùn)算的方法:

  • add ——加法
  • subtract ——減法
  • divide ——除法,有可能除不盡,必須顯式聲明保留小數(shù)位數(shù)避免拋出ArithmeticException異常
  • multiply ——乘法
@Test
public void whenPerformingArithmetic_thenExpectedResult() {
  BigDecimal bd1 = new BigDecimal("4.0");
  BigDecimal bd2 = new BigDecimal("2.0");

  BigDecimal sum = bd1.add(bd2);
  BigDecimal difference = bd1.subtract(bd2);
  BigDecimal quotient = bd1.divide(bd2);
  BigDecimal product = bd1.multiply(bd2);

  assertTrue(sum.compareTo(new BigDecimal("6.0")) == 0);
  assertTrue(difference.compareTo(new BigDecimal("2.0")) == 0);
  assertTrue(quotient.compareTo(new BigDecimal("2.0")) == 0);
  assertTrue(product.compareTo(new BigDecimal("8.0")) == 0);
}

四舍五入

既然是數(shù)學(xué)運(yùn)算就不得不講四舍五入。比如我們在金額計(jì)算中很容易遇到最終結(jié)算金額為人民幣22.355的情況。因?yàn)樨泿艣]有比分更低的單位所以我們要使用精度和舍入模式規(guī)則對數(shù)字進(jìn)行剪裁。java提供有兩個(gè)類控制舍入行為RoundingMode和MathContext 。MathContext執(zhí)行的是IEEE 754R標(biāo)準(zhǔn)目前不太明白其使用場景,我們使用的比較多的是枚舉RoundingMode。它提供了八種模式:

RoundingMode.UP:以小數(shù)位為原點(diǎn) 是正數(shù)取右邊,負(fù)數(shù)取左邊
RoundingMode.DOWN:以小數(shù)位為原點(diǎn) 也就是正數(shù)取左邊,負(fù)數(shù)取右邊
RoundingMode.FLOOR:取左邊最近的正數(shù)
RoundingMode.CEILING:取右邊最近的整數(shù)
RoundingMode.HALF_DOWN:五舍六入,負(fù)數(shù)先取絕對值再五舍六入再負(fù)數(shù)
RoundingMode.HALF_UP:四舍五入,負(fù)數(shù)原理同上
RoundingMode.HALF_EVEN:這個(gè)比較繞,整數(shù)位若是奇數(shù)則四舍五入,若是偶數(shù)則五舍六入
RoundingMode.ROUND_UNNECESSARY:不需要取整,如果存在小數(shù)位,就拋ArithmeticException 異常

格式化

數(shù)字格式化可通過操作類java.text.NumberFormat和java.text.DecimalFormat提供的api進(jìn)行操作。其實(shí)我們只需要使用java.text.DecimalFormat,因?yàn)樗砹薔umberFormat。我們來看一下它們的api:

NumberFormat

NumberFormat.getInstance(Locale)、getNumberInstance(Locale)。返回指定語言環(huán)境的通用數(shù)值格式。
NumberFormat.getCurrencyInstance(Locale)。返回指定語言環(huán)境的貨幣格式。
NumberFormat.getPercentInstance(Locale)。返回指定語言環(huán)境的百分比格式。
NumberFormat.getIntegerInstance(Locale)。返回指定語言環(huán)境的整數(shù)數(shù)值格式。
NumberFormat.setMinimumIntegerDigits(int)。設(shè)置數(shù)的整數(shù)部分所允許的最小位數(shù)。
NumberFormat.setMaximumIntegerDigits(int)。設(shè)置數(shù)的整數(shù)部分所允許的最大位數(shù)。
NumberFormat.setMinimumFractionDigits(int)。設(shè)置最少小數(shù)點(diǎn)位數(shù),不足的位數(shù)以0補(bǔ)位,超出的話按實(shí)際位數(shù)輸出。
NumberFormat.setMaximumFractionDigits(int)。設(shè)置最多保留小數(shù)位數(shù),不足不補(bǔ)0。

DecimalFormat

DecimalFormat除了能代理上面的NumberFormat以外,還提供了基于pattern字符串的格式化風(fēng)格,有點(diǎn)類似格式化時(shí)間一樣。我們來看看pattern的規(guī)則:

  • “0”——表示一位數(shù)值,如沒有,顯示0。如“0000.0000”,整數(shù)位或小數(shù)位>4,按實(shí)際輸出,<4整數(shù)位前面補(bǔ)0小數(shù)位后面補(bǔ)0,湊足4位。
  • “#”——表示任意位數(shù)的整數(shù)。如沒有,則不顯示。在小數(shù)點(diǎn)位使用,只表示一位小數(shù),超出部分四舍五入。如:“#”:無小數(shù),小數(shù)部分四舍五入?!?#”:整數(shù)部分不變,一位小數(shù),四舍五入。“.##”:整數(shù)部分不變,二位小數(shù),四舍五入。
  • “.”——表示小數(shù)點(diǎn)。注意一個(gè)pattern中只能出現(xiàn)一次,超過一次將格式化異常。
  • “,”——與模式“0”一起使用,表示逗號。注意一定不能在小數(shù)點(diǎn)后用,否則格式化異常。

總結(jié)

今天對BigDecimal進(jìn)行了總結(jié)歸納,這篇文章建議你收藏備用,也可以轉(zhuǎn)給其他需要的同學(xué)。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java Unsafe詳細(xì)解析

    java Unsafe詳細(xì)解析

    Unsafe為我們提供了訪問底層的機(jī)制,這種機(jī)制僅供java核心類庫使用,而不應(yīng)該被普通用戶使用。但是,為了更好地了解java的生態(tài)體系,我們應(yīng)該去學(xué)習(xí)它,去了解它,不求深入到底層的C/C++代碼,但求能了解它的基本功能。下面小編來和大家一起學(xué)習(xí)
    2019-05-05
  • Java?HashTable與Collections.synchronizedMap源碼深入解析

    Java?HashTable與Collections.synchronizedMap源碼深入解析

    HashTable是jdk?1.0中引入的產(chǎn)物,基本上現(xiàn)在很少使用了,但是會在面試中經(jīng)常被問到。本文就來帶大家一起深入了解一下Hashtable,需要的可以參考一下
    2022-11-11
  • java實(shí)現(xiàn)的順時(shí)針/逆時(shí)針打印矩陣操作示例

    java實(shí)現(xiàn)的順時(shí)針/逆時(shí)針打印矩陣操作示例

    這篇文章主要介紹了java實(shí)現(xiàn)的順時(shí)針/逆時(shí)針打印矩陣操作,涉及java基于數(shù)組的矩陣存儲、遍歷、打印輸出等相關(guān)操作技巧,需要的朋友可以參考下
    2019-12-12
  • 關(guān)于spring中單例Bean引用原型Bean產(chǎn)生的問題及解決

    關(guān)于spring中單例Bean引用原型Bean產(chǎn)生的問題及解決

    這篇文章主要介紹了關(guān)于spring中單例Bean引用原型Bean產(chǎn)生的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 詳解Java如何實(shí)現(xiàn)多線程步調(diào)一致

    詳解Java如何實(shí)現(xiàn)多線程步調(diào)一致

    本章節(jié)主要講解另外兩個(gè)線程同步器:CountDownLatch和CyclicBarrier的用法,使用場景以及實(shí)現(xiàn)原理,感興趣的小伙伴可以了解一下
    2023-07-07
  • Java自動(dòng)拆裝箱簡單介紹

    Java自動(dòng)拆裝箱簡單介紹

    這篇文章主要為大家詳細(xì)介紹了Java自動(dòng)拆裝箱的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • mybatis 有時(shí)update語句執(zhí)行無效的解決方案

    mybatis 有時(shí)update語句執(zhí)行無效的解決方案

    這篇文章主要介紹了在項(xiàng)目里mybatis有時(shí)update語句執(zhí)行無效的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring事務(wù)Transaction配置的五種注入方式詳解

    Spring事務(wù)Transaction配置的五種注入方式詳解

    這篇文章主要介紹了Spring事務(wù)Transaction配置的五種注入方式詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • Springboot jar文件如何打包zip在linux環(huán)境運(yùn)行

    Springboot jar文件如何打包zip在linux環(huán)境運(yùn)行

    這篇文章主要介紹了Springboot jar文件如何打包zip在linux環(huán)境運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java實(shí)現(xiàn)添加,讀取和刪除Excel圖片的方法詳解

    Java實(shí)現(xiàn)添加,讀取和刪除Excel圖片的方法詳解

    本文介紹在Java程序中如何添加圖片到excel表格,以及如何讀取、刪除excel表格中已有的圖片。文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下
    2022-05-05

最新評論

静乐县| 新乐市| 岳普湖县| 浙江省| 资中县| 彩票| 德清县| 黎平县| 壶关县| 汉阴县| 廊坊市| 黑龙江省| 江口县| 威宁| 鸡东县| 界首市| 澎湖县| 乌拉特后旗| 临泽县| 井陉县| 家居| 六安市| 密山市| 中宁县| 日土县| 安西县| 措美县| 同仁县| 北安市| 辽宁省| 定州市| 买车| 醴陵市| 连江县| 阿合奇县| 榆林市| 潜山县| 武川县| 东乌珠穆沁旗| 深州市| 襄樊市|