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,但對于浮點(diǎn)數(shù)的計(jì)算而言卻是無限接近于1,但與1不等。
當(dāng)我們需要對float的數(shù)據(jù)進(jìn)行計(jì)算的時(shí)候,我們可以使用第三方的decimal包來解決這個(gè)問題。
2. decimal的應(yīng)用場景
decimal的應(yīng)用場景主要出現(xiàn)在對float浮點(diǎn)數(shù)進(jìn)行加減乘除操作的時(shí)候,尤其是對于銀行金融一塊的業(yè)務(wù),如果精度丟失,一筆交易上面的損失可以忽略不計(jì),但當(dāng)交易的規(guī)模達(dá)到幾千萬或者億甚至幾十億的時(shí)候,這個(gè)時(shí)候的損失就會大的嚇人了。
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ù)字,對于絕大多數(shù)的項(xiàng)目精度要求是足夠的,簡而言之,decimal可以解決我們絕大多數(shù)的浮點(diǎn)數(shù)精度計(jì)算場景。
對于上面精度丟失的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í)用的場景
使用decimal的時(shí)候,切記浮點(diǎn)數(shù)計(jì)算所有數(shù)據(jù)的初始化必須通過decimal進(jìn)行,否則還是會導(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可以對計(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())
?? ?// 取絕對值
?? ?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對于浮點(diǎn)數(shù)的計(jì)算提供了極大的便利性,讓我們在使用浮點(diǎn)數(shù)進(jìn)行大小計(jì)算的時(shí)候不用擔(dān)心精度丟失的問題,尤其是對于金融行業(yè),精度丟失造成資損就是很重大的生產(chǎn)事故了。
對decimal有一些基本的了解,當(dāng)我們在工作中有場景需要使用到浮點(diǎn)數(shù)的計(jì)算的時(shí)候,可以直接使用decimal來幫助我們快速完善計(jì)算的邏輯。
到此這篇關(guān)于go語言中decimal的用法詳解的文章就介紹到這了,更多相關(guān)go語言decimal用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語言實(shí)現(xiàn)簡易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能
這篇文章主要介紹了go語言實(shí)現(xiàn)簡易比特幣系統(tǒng)之交易簽名及校驗(yàn)功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE) 簡介附go實(shí)現(xiàn)示例代碼
EventSource是一種非常有用的 API,適用于許多實(shí)時(shí)應(yīng)用場景,它提供了一種簡單而可靠的方式來建立服務(wù)器推送連接,并實(shí)現(xiàn)實(shí)時(shí)更新和通知,這篇文章主要介紹了實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE)簡介附go實(shí)現(xiàn)示例,需要的朋友可以參考下2024-03-03

