开发者

Golang使用Decimal库避免运算中精度损失详细步骤

开发者 https://www.devze.com 2023-11-21 10:51 出处:网络 作者: eRain
目录前言一、Decimal库是什么?二、使用步骤1.引入库2.Decimal库的使用总结前言
目录
  • 前言
  • 一、Decimal库是什么?
  • 二、使用步骤
    • 1.引入库
    • 2.Decimal库的使用
  • 总结

    前言

    我们在项目中涉及到数值计算时,如果直接使用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程序数值计算时避免精度损失的包,引用官方的描述:

    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库“只能”表示小数点后最多2^31位的数字。当然,这对于绝大部分项目来说足够了。

    二、使用步骤

    1.引入库

    下载包:

    go get github.com/shopspring/decimal

    go代码中引入包:

    import "github.com/shopspring/decimal"

    2.Decimal库的使用

    使用decimal后,上面例子的代码就应该这样写:

    package main
    
    import (
    	"fmt"
    	"githpythonub.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
    }

    之后对于各种数字的计算就会变得得心应手:

    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)
    
    	// 对于保留小数的处理
    	pi := decimal.NewFromFloat(3.1415926535897932384626)
    	pi1 := pi.Round(3)    // 对pi值四舍五入保留3位小数
    	fmt.Println(pi1)       // 3.142
    	pi2 := pi.Truncate(3) // 对pi值保留3位小数之后直接舍弃
    	fmt.Println(pi2)       // 3.141
    }

    对于数值变量类型的转换也游刃有余了:

    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() // 舍去小数取整
    fmt.Println(c)  // int64 69
    
    b = decimal.NewFromInt(c).String()
    fmt.Println(b) // string 69
    
    c = d.Round(0).IntPart() // 不保留小数四舍五入取整
    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(npython2)        // n1 是否大于 n2
    n1.GreaterThanOrEqual(n2) // n1 是否大于或等于 n2
    n3.IsZero()               // n3 是否为0
    

    总结

    Decimal库会给我们项目中用到数值计算时提供极大的便利和安全性。

    最后需要注意的一点是,使用Decimal库的变量数据类型全部为decimal.Decimal,同样decimal.Decimal也可以作为声明变量时的数据类型使用,所以记得在最后做变量赋值时转换为需要的数据类型。

    package m编程客栈ain
    
    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, pythonreflect.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 = decimajsl.Decimal
    }
    

    到此这篇关于Golang使用Decimal库避免运算中精度损失的文章就介绍到这了,更多相关Golang避免运算精度损失内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号