紙上談兵 BigDecimal原始碼學習

2021-08-21 02:30:16 字數 2100 閱讀 8471

一、bigdecimal宣告

新來同事看到我們**中bigdeciaml用法,感覺比較奇怪,由此引出了這篇文章

使用下面方式宣告bigdecimal時,會出現精度問題

bigdecimal bd3 = new bigdecimal(0.1d);

推薦用法

bigdecimal bd1 = new bigdecimal("0.1");

bigdecimal bd2 = bigdecimal.valueof(1d);

用以上方法就不會出問題精度問題

bigdecimal.valueof() 檢視原始碼就可以知道,也是使用的new bigdecimal("0.1")建構函式

注意:bigdecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生乙個新的物件,所以在做加減乘除運算時千萬要儲存操作後的值。

二、為什麼bigdecimal使用double或float會出現精度問題?

原因:十進位制轉二進位制的演算法導致轉為二進位制時,某些數字會永遠不為零

十進位制轉二進位制方法

整數部分:除以2,取出餘數,商繼續除以2,直到得到0為止,將取出的餘數逆序

小數部分:乘以2,然後取出整數部分,將剩下的小數部分繼續乘以2,然後再取整數部分,一直取到小數部分為零為止。如果永遠不為零,則按要求保留足夠位數的小數,最後一位做0舍1入。將取出的整數順序排列

看了這個我想大家就都明白了,double或float之類的浮點數,轉為二進位制儲存時某些數字會永遠不為零

十進位制轉二進位制例子:

整數部分: 我相信你會,你可以的。不會可以看我下面的參考資料

小數部分:乘以2,取整,小數部分繼續乘以2,取整,得到小數部分0為止,將整數順序排列

0.1x2=0.2 取整0,小數部分是2

0.2x2=0.4 取整0,小數部分是4

0.4x2=0.8 取整0,小數部分是8

0.8x2=1.6 取整1,小數部分是6

0.6x2=1.2 取整1,小數部分是2

。。。。。你會發出與前面重複了,會一直不停迴圈下去

三、為什麼bigdecimal使用string不會出現精度問題

現在我們明白為什麼用double,float 出現出精度問題。現在我們要看一下bigdecimal對string做了什麼不會出現精度問題

首先: 程式就是資料結構與演算法

通過debug構造方法,我們可以了解,bigdecimal底層資料結構主要是由下面四個屬性值組成.

int scale; //有多少位小數(即小數點後有多少位)

int precision; //總工有多少位數字

long intcompact; //字串去掉小數點後,轉為long的值,只有當傳的字串長度小於18時才使用該言

biginteger intval; //當傳的字串長度大於等於18時才使用biginteger表示數字

以new bigdecimal("12.12")為例

scale值為2

precision值為4

intcompact值為1212

intval值為空。之所以為空是因為字串長度沒有超18位,所以不啟用biginteger表示

看到這進而其實大家應該明白了,bigdecimal將string轉為了long或biginteger來進行計算。

四、使用idea debug bigdeciaml原始碼出現的奇怪現象

**:bigdecimal bd1 = new bigdecimal("1");

system.out.println("bd1:" + bd1);

上面的**,不進行debug列印的結果是"bd1:1"

我們在idea中同時在bigdeciaml類的411行打上斷點(**:if (offset + len > in.length || offset < 0) ,並非一定在這裡打上斷點,其實只要是在原始碼中加上斷點能讓這段**走到debug即可,但不要在tostring方法上加),然後debug執行,到了點斷處,可以直接往下走,讓**執行完,你會發現結果是"bd1:0"。

原因是什麼我還不明白,估計是idea的debug存在bug導致該問題產生  

五、todo:

加、減、乘、除,每個具體原始碼如何實現

參考:

紙上談兵 佇列 queue

佇列 queue 是乙個簡單而常見的資料結構。佇列也是有序的元素集合。佇列最大的特徵是first in,first out fifo,先進先出 即先進入佇列的元素,先被取出。這一點與棧 stack 形成有趣的對比。佇列在生活中很常見,排隊買票 排隊等車 先到的人先得到服務並離開佇列,後來的人加入到佇...

紙上談兵 佇列 queue

佇列 queue 是乙個簡單而常見的資料結構。佇列也是有序的元素集合。佇列最大的特徵是first in,first out fifo,先進先出 即先進入佇列的元素,先被取出。這一點與棧 stack 形成有趣的對比。佇列在生活中很常見,排隊買票 排隊等車 先到的人先得到服務並離開佇列,後來的人加入到佇...

紙上談兵 棧 stack

棧 stack 是簡單的資料結構,但在計算機中使用廣泛。它是有序的元素集合。棧最顯著的特徵是lifo last in,first out,後進先出 當我們往箱子裡存放一疊書時,先存放的書在箱子下面,我們必須將後存放的書取出來,才能看到和拿出早先存放的書。棧中的每個元素稱為乙個frame。而最上層元素...