go語言中decimal的用法詳解
decimal是為了解決Golang中浮點(diǎn)數(shù)計(jì)算時(shí)精度丟失問題而生的一個(gè)庫,使用decimal庫我們可以避免在go中使用浮點(diǎn)數(shù)出現(xiàn)精度丟失的問題。
github地址:https://github.com/shopspring/decimal
1. 精度丟失的case
func TestFloat(t *testing.T) { a := 1100.1 b := a * 100 fmt.Println(b) // should be: 110010 output: 110009.99999999999 }
上面的精度就發(fā)生了丟失,浮點(diǎn)數(shù)的位數(shù)雖然我們看到的是1100.1,但對(duì)于浮點(diǎn)數(shù)的計(jì)算而言卻是無限接近于1,但與1不等。
當(dāng)我們需要對(duì)float的數(shù)據(jù)進(jìn)行計(jì)算的時(shí)候,我們可以使用第三方的decimal包來解決這個(gè)問題。
2. decimal的應(yīng)用場(chǎng)景
decimal的應(yīng)用場(chǎng)景主要出現(xiàn)在對(duì)float浮點(diǎn)數(shù)進(jìn)行加減乘除操作的時(shí)候,尤其是對(duì)于銀行金融一塊的業(yè)務(wù),如果精度丟失,一筆交易上面的損失可以忽略不計(jì),但當(dāng)交易的規(guī)模達(dá)到幾千萬或者億甚至幾十億的時(shí)候,這個(gè)時(shí)候的損失就會(huì)大的嚇人了。
3. 使用decimal
使用decimal第一步是引入這個(gè)包,decimal,在官方的描述中,這個(gè)包的功能描述如下:
Arbitrary-precision fixed-point decimal numbers in go.
Note: Decimal library can “only” represent numbers with a maximum of 2^31 digits after the decimal point.
go中任意精度定點(diǎn)的十進(jìn)制數(shù)
注意:十進(jìn)制庫"只能"表示小數(shù)點(diǎn)后最多2^31位的數(shù)字。
小數(shù)點(diǎn)后2^31位數(shù)字,對(duì)于絕大多數(shù)的項(xiàng)目精度要求是足夠的,簡(jiǎn)而言之,decimal可以解決我們絕大多數(shù)的浮點(diǎn)數(shù)精度計(jì)算場(chǎng)景。
對(duì)于上面精度丟失的case,當(dāng)我們引入decimal包之后,我們可以得到正確的結(jié)果。
func TestDecimalOne(t *testing.T){ a := 1100.1 b := 100 d := decimal.NewFromFloat(a) result := d.Mul(decimal.NewFromInt(int64(b))) fmt.Println(result) // should be: 110010, output: 110010 }
計(jì)算結(jié)果的精度沒有丟失,計(jì)算結(jié)果正確。
4. decimal其他實(shí)用的場(chǎng)景
使用decimal的時(shí)候,切記浮點(diǎn)數(shù)計(jì)算所有數(shù)據(jù)的初始化必須通過decimal進(jìn)行,否則還是會(huì)導(dǎo)致精度的丟失,為什么這么說呢,看看下面的例子你就明白了。
import ( ?? ?"fmt" ?? ?"github.com/shopspring/decimal" ?? ?"testing" ) func TestDecimal(t *testing.T) { ?? ?x := 0.28 ?? ?// this will cause the multi result has error ?? ?// output should be 28, but actually 28.000000000000004(error) ?? ?errorMul := decimal.NewFromFloat(x * 100).String() }
上面的case就是因?yàn)?00沒有使用decimal進(jìn)行初始化導(dǎo)致最后計(jì)算的精度被擴(kuò)大了。正確的處理方式如下:
import ( ?? ?"fmt" ?? ?"github.com/shopspring/decimal" ?? ?"testing" ) func TestDecimal(t *testing.T) { ?? ?x := 0.28 ?? ?// the correct operate number multi is use the decimal Mul method. ?? ?correctMul := decimal.NewFromFloat(x).Mul(decimal.NewFromInt(100)).String() ? ? fmt.Println(correctMul) // output: 28 }
4.1 獲取結(jié)果的整數(shù)部分
使用IntPart可以獲取到浮點(diǎn)數(shù)計(jì)算結(jié)果的整數(shù)部分。
func TestDecimalTwo(t *testing.T){ a := 0.01234 b := 100 // 0.01234 * 100 = 1.234, int part=1, output=1 fmt.Println(decimal.NewFromFloat(a).Mul(decimal.NewFromInt(int64(b))).IntPart()) }
4.2 小數(shù)點(diǎn)后填充
使用IntPart可以對(duì)計(jì)算后的數(shù)據(jù)進(jìn)行小數(shù)點(diǎn)位數(shù)的補(bǔ)零填充。
func TestDecimalThree(t *testing.T){ a := 0.012 b := 100 x := decimal.NewFromFloat(a).Mul(decimal.NewFromInt(int64(b))) // 小數(shù)點(diǎn)后的位數(shù)填充, 0.012*100=1.2, 填充3位,因?yàn)橐呀?jīng)有一位了,填充兩個(gè)0, 1.200 fmt.Println(x.StringFixed(3)) }
4.3 比較數(shù)字的大小
浮點(diǎn)數(shù)的比較decimal提供了一些比較有用的函數(shù)方法,這里列舉了一部分。
import ( ?? ?"fmt" ?? ?"github.com/shopspring/decimal" ?? ?"testing" ) func TestDecimalFour(t *testing.T) { ?? ?a := decimal.NewFromFloat(-1.11) ?? ?b := decimal.NewFromInt(3) ?? ?c, _ := decimal.NewFromString("2.023") ?? ?// 是否是負(fù)數(shù) ?? ?fmt.Println(a.IsNegative()) ?? ?// 取絕對(duì)值 ?? ?fmt.Println(a.Abs()) ?? ?// 比較是否相等 ?? ?fmt.Println(a.Equal(b)) ?? ?// 比較小于 ?? ?fmt.Println(a.LessThan(b)) ?? ?// 比較小于等于 ?? ?fmt.Println(a.LessThanOrEqual(b)) ?? ?// 比較大于等于 ?? ?fmt.Println(b.GreaterThanOrEqual(a)) ?? ?// 是否是0 ?? ?fmt.Println(c.IsZero()) }
5 小結(jié)
decimal對(duì)于浮點(diǎn)數(shù)的計(jì)算提供了極大的便利性,讓我們?cè)谑褂酶↑c(diǎn)數(shù)進(jìn)行大小計(jì)算的時(shí)候不用擔(dān)心精度丟失的問題,尤其是對(duì)于金融行業(yè),精度丟失造成資損就是很重大的生產(chǎn)事故了。
對(duì)decimal有一些基本的了解,當(dāng)我們?cè)诠ぷ髦杏袌?chǎng)景需要使用到浮點(diǎn)數(shù)的計(jì)算的時(shí)候,可以直接使用decimal來幫助我們快速完善計(jì)算的邏輯。
到此這篇關(guān)于go語言中decimal的用法詳解的文章就介紹到這了,更多相關(guān)go語言decimal用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語言實(shí)現(xiàn)簡(jiǎn)易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能
這篇文章主要介紹了go語言實(shí)現(xiàn)簡(jiǎn)易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE) 簡(jiǎn)介附go實(shí)現(xiàn)示例代碼
EventSource是一種非常有用的 API,適用于許多實(shí)時(shí)應(yīng)用場(chǎng)景,它提供了一種簡(jiǎn)單而可靠的方式來建立服務(wù)器推送連接,并實(shí)現(xiàn)實(shí)時(shí)更新和通知,這篇文章主要介紹了實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE)簡(jiǎn)介附go實(shí)現(xiàn)示例,需要的朋友可以參考下2024-03-03Golang中context庫的高級(jí)應(yīng)用
context庫不僅對(duì)于提升代碼的效率和性能至關(guān)重要,而且還幫助開發(fā)者在復(fù)雜的系統(tǒng)中保持代碼的清晰和可維護(hù)性,下面我們就來看看context庫的高級(jí)應(yīng)用吧2024-01-01