摘要:除法的精度問題在使用的除法時,遇到一個鬼畜的問題,本以為的精度計算,結果使用返回,當然最終發現還是自己的使用姿勢不對導致的,因此記錄一下,避免后面重蹈覆轍問題拋出在使用做高精度的除法時,一不注意遇到了一個小問題,如下上面的輸出是什么
BigDecimal除法的精度問題
在使用BigDecimal的除法時,遇到一個鬼畜的問題,本以為的精度計算,結果使用返回0,當然最終發現還是自己的使用姿勢不對導致的,因此記錄一下,避免后面重蹈覆轍
I. 問題拋出在使用BigDecimal做高精度的除法時,一不注意遇到了一個小問題,如下
@Test public void testBigDecimal() { BigDecimal origin = new BigDecimal(541253); BigDecimal now = new BigDecimal(12389431); BigDecimal val = origin.divide(now, RoundingMode.HALF_UP); System.out.println(val); origin = new BigDecimal(541253); now = new BigDecimal(12389431.3); val = origin.divide(now, RoundingMode.HALF_UP); System.out.println(val); origin = new BigDecimal(541253.4); now = new BigDecimal(12389431); val = origin.divide(now, RoundingMode.HALF_UP); System.out.println(val); }
上面的輸出是什么 ?
0 0 0.043686703610520937021487456961257
為什么前面兩個會是0呢,如果直接是 541253 / 12389431 = 0 倒是可以理解, 但是BigDecimal不是高精度的計算么,講道理不應該不會出現這種整除的問題吧
我們知道在BigDecimal做觸發時,可以指定保留小數的參數,如果加上這個,是否會不一樣呢?
BigDecimal origin = new BigDecimal(541253); BigDecimal now = new BigDecimal(12389431); BigDecimal val = origin.divide(now, 5, RoundingMode.HALF_UP); System.out.println(val);
輸出結果為:
0.04369
所以說在指定了保留小數之后,則沒有問題,所以大膽的猜測一下,是不是上面的幾種case中,由于scale值沒有指定時,默認值不一樣,從而導致最終結果的精度不同呢?
簡單的深入源碼分析一下,執行的方式為 origin.divide(now, RoundingMode.HALF_UP);, 所以這個scale參數就瞄準origin對象,而這個對象,就只能去分析它的構造了,因為沒有其他的地方使用
II. 源碼定位 1. 整形傳參構造分析下面這一行, 直接進入源碼
BigDecimal origin = new BigDecimal(541253);
很明顯的int傳參構造,進去簡單看一下
// java.math.BigDecimal#BigDecimal(int) public BigDecimal(int val) { this.intCompact = val; this.scale = 0; this.intVal = null; } public BigDecimal(long val) { this.intCompact = val; this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null; this.scale = 0; }
so,很明確的知道默認的scale為0,也就是說當origin為正數時,以它進行的除法,不現實指定scale參數時,最終返回的都是沒有小數的,同樣看一眼,還有long的傳參方式, BigInteger也一樣
2. 浮點傳參接下來就是浮點的scale默認值確認了,這個構造相比前面的復雜一點,源碼就不貼了,太長,也看不太懂做了些啥,直接用猥瑣一點的方式,進入debug模式,單步執行
@Test public void testBigDecimal() { BigDecimal origin = new BigDecimal(541253.0); BigDecimal now = new BigDecimal(12389431.1); BigDecimal tmp = new BigDecimal(0.0); }
根據debug的結果,第一個,scale為0; 第二個scale為29, 第三個scale為0
3. String傳參依然是一大串的邏輯,同樣采用單步debug的方式試下
@Test public void testBigDecimal() { BigDecimal origin = new BigDecimal("541253.0"); BigDecimal now = new BigDecimal("12389431.1"); BigDecimal t = new BigDecimal("0.0"); }
上面三個的scale都是1
4. 小結對于BigDecimal進行除法運算時,最好指定其scale參數,不然可能會有坑
對于BigDecimla的scale初始化的原理,有待深入看下BigDecimal是怎么實現的
最后貼一張乘法的圖作為收尾
II. 其他 1. 一灰灰Blog: https://liuyueyi.github.io/he...一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
2. 聲明盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
微博地址: 小灰灰Blog
QQ: 一灰灰/3302797840
3. 掃描關注文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71492.html
摘要:原因至于問題產生的原因,或者關于問題的更詳細的描述,大家請看下面幾個文章浮點運算浮點值運算舍入誤差基礎浮點數四則運算精度丟失問題解決方案這里主要討論一下解決方案的問題,上面幾篇文章的解決思路,都是重寫加法減法乘法和除法運算。 問題背景 在 chrome 瀏覽器中調出開發者工具,在控制臺窗口輸入下面的表達式: 0.1 + 0.2 // 期望:0.3,結果:0.300...
摘要:使用,保證精度的同時,能精準的進行四舍六入計算。類精確的數學運算使用來實現精準度因為精度的原因構造方法的結果有一定的不可預知性,例如因此建議使用。算法規則四舍六入五考慮,五后非零就進一,五后皆零看奇偶,五前為偶應舍去,五前為奇要進一。 四舍六入計算 算法規則: 四舍六入五考慮, 五后非零就進一, 五后皆零看奇偶, 五前為偶應舍去, 五前為奇要進一。 使用BigDecimal,保證精度的...
摘要:前言在數據敏感的業務場景中,常常會碰到數據精度問題,尤其在金額顯示占比統計等地方,該問題尤為顯著。計算機原理真香數值的精度問題,其實是非常基礎的計算機原理知識。前言 在數據敏感的業務場景中,常常會碰到數據精度問題,尤其在金額顯示、占比統計等地方,該問題尤為顯著。由于數據的每一位有效數字都包含真實的業務語義,一點點偏差甚至可能影響業務決策,這讓問題的嚴重性上升了幾個階梯。 那,什么是精度丟失...
摘要:局部變量聲明在函數內部的變量。在作用域范圍內不能出現命名沖突。 java編程規范: 1.良好的標識符的命名 保留字不能作為標識符命名: class、public、static..., goto,const 區分大小寫:helloWorld、HelloWorld 2.良好的注釋習慣 3.良好的縮進:沒遇到一個代碼塊縮進一次(一個tab鍵) 變量:代...
閱讀 3298·2021-09-08 09:45
閱讀 1255·2019-08-30 15:53
閱讀 1527·2019-08-30 14:12
閱讀 986·2019-08-29 17:01
閱讀 2574·2019-08-29 15:35
閱讀 398·2019-08-29 13:09
閱讀 1975·2019-08-29 12:32
閱讀 3088·2019-08-26 18:37