Golang使用Decimal庫避免運算中精度損失詳細步驟
前言
我們在項目中涉及到數(shù)值計算時,如果直接使用golang的運算符,會造成精度的損失,例如:
a := 1136.1 b := a * 100 fmt.Println(b) // 正確結果應該是 113610 但輸出 113609.99999999999 c := 1.7 fmt.Println(a - c) // 正確結果應該是 1134.4 但輸出 1134.3999999999999 fmt.Println(b - c) // 正確結果應該是 113608.3 但輸出 113608.29999999999
那么如何避免這種情況呢?golang中沒有提供對于精度運算相應的包。這里需要用到第三方的decimal包了。
一、Decimal庫是什么?
是一個第三方提供的用于go程序數(shù)值計算時避免精度損失的包,引用官方的描述:
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.
注意這里有個Note:Decimal庫“只能”表示小數(shù)點后最多2^31位的數(shù)字。當然,這對于絕大部分項目來說足夠了。
二、使用步驟
1.引入庫
下載包:
go get github.com/shopspring/decimal
go代碼中引入包:
import "github.com/shopspring/decimal"
2.Decimal庫的使用
使用decimal后,上面例子的代碼就應該這樣寫:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
a := decimal.NewFromFloat(1136.1)
b := a.Mul(decimal.NewFromInt(100))
fmt.Println(b) // 正確輸出 113610
c := decimal.NewFromFloat(1.7)
fmt.Println(a.Sub(c)) // 正確輸出 1134.4
fmt.Println(b.Sub(c)) // 正確輸出 113608.3
}之后對于各種數(shù)字的計算就會變得得心應手:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
a := decimal.NewFromFloat(1.52)
b := decimal.NewFromFloat(0.02)
// 加減乘除運算
c := a.Add(b) // 1.52 + 0.02 = 1.54
d := a.Sub(b) // 1.52 - 0.02 = 1.5
e := a.Mul(b) // 1.52 * 0.02 = 0.0304
f := a.Div(b) // 1.52 / 0.02 = 76
fmt.Println(a, b, c, d, e, f)
// 對于保留小數(shù)的處理
pi := decimal.NewFromFloat(3.1415926535897932384626)
pi1 := pi.Round(3) // 對pi值四舍五入保留3位小數(shù)
fmt.Println(pi1) // 3.142
pi2 := pi.Truncate(3) // 對pi值保留3位小數(shù)之后直接舍棄
fmt.Println(pi2) // 3.141
}對于數(shù)值變量類型的轉換也游刃有余了:
var a float64
var b = "69.77"
var c int64
d, err := decimal.NewFromString(b)
if err != nil {
fmt.Println(err.Error())
}
a, _ = d.Float64()
fmt.Println(a) // float64 69.77
c = d.IntPart() // 舍去小數(shù)取整
fmt.Println(c) // int64 69
b = decimal.NewFromInt(c).String()
fmt.Println(b) // string 69
c = d.Round(0).IntPart() // 不保留小數(shù)四舍五入取整
fmt.Println(c) // int64 70
這里列出一些常用的方法:
n1 := decimal.NewFromFloat(-1.23)
n2 := decimal.NewFromInt(3)
n3, _ := decimal.NewFromString("0")
n1.Abs() // 取絕對值
n1.Equal(n2) // n1 是否與 n2 相等
n1.LessThan(n2) // n1 是否小于 n2
n1.LessThanOrEqual(n2) // n1 是否小于或等于 n2
n1.GreaterThan(n2) // n1 是否大于 n2
n1.GreaterThanOrEqual(n2) // n1 是否大于或等于 n2
n3.IsZero() // n3 是否為0
總結
Decimal庫會給我們項目中用到數(shù)值計算時提供極大的便利和安全性。
最后需要注意的一點是,使用Decimal庫的變量數(shù)據類型全部為decimal.Decimal,同樣decimal.Decimal也可以作為聲明變量時的數(shù)據類型使用,所以記得在最后做變量賦值時轉換為需要的數(shù)據類型。
package main
import (
"fmt"
"github.com/shopspring/decimal"
"reflect"
)
func main() {
n1 := decimal.NewFromFloat(3.14)
var n2 string
var n3 float64
var n4 int64
var n5 decimal.Decimal
n2 = n1.String()
n3, _ = n1.Float64()
n4 = n1.IntPart()
fmt.Printf("n1 = %v, type = %v\n", n1, reflect.TypeOf(n1).String())
// n1 = 3.14, type = decimal.Decimal
fmt.Printf("n2 = %v, type = %v\n", n2, reflect.TypeOf(n2).String())
// n2 = 3.14, type = string
fmt.Printf("n3 = %v, type = %v\n", n3, reflect.TypeOf(n3).String())
// n3 = 3.14, type = float64
fmt.Printf("n4 = %v, type = %v\n", n4, reflect.TypeOf(n4).String())
// n4 = 3, type = int64
fmt.Printf("n5 = %v, type = %v\n", n5, reflect.TypeOf(n5).String())
// n5 = 0, type = decimal.Decimal
}
到此這篇關于Golang使用Decimal庫避免運算中精度損失的文章就介紹到這了,更多相關Golang避免運算精度損失內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go+Kafka實現(xiàn)延遲消息的實現(xiàn)示例
本文主要介紹了Go+Kafka實現(xiàn)延遲消息的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
go語言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等
這篇文章主要為大家介紹了go語言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Go?chassis云原生微服務開發(fā)框架應用編程實戰(zhàn)
這篇文章主要為大家介紹了Go?chassis云原生微服務開發(fā)框架應用編程實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
Go Slice進行參數(shù)傳遞如何實現(xiàn)詳解
這篇文章主要為大家介紹了Go Slice進行參數(shù)傳遞如何實現(xiàn)的過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12

