go语言中decimal的用法详解

目录
  • 1. 精度丢失的case
  • 2. decimal的应用场景
  • 3. 使用decimal
  • 4. decimal其他实用的场景
    • 4.1 获取结果的整数部分
    • 4.2 小数点后填充
    • 4.3 比较数字的大小
  • 5 小结

decimal是为了解决Golang中浮点数计算时精度丢失问题而生的一个库,使用decimal库我们可以避免在go中使用浮点数出现精度丢失的问题。

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
}

上面的精度就发生了丢失,浮点数的位数虽然我们看到的是1100.1,但对于浮点数的计算而言却是无限接近于1,但与1不等。

当我们需要对float的数据进行计算的时候,我们可以使用第三方的decimal包来解决这个问题。

2. decimal的应用场景

decimal的应用场景主要出现在对float浮点数进行加减乘除操作的时候,尤其是对于银行金融一块的业务,如果精度丢失,一笔交易上面的损失可以忽略不计,但当交易的规模达到几千万或者亿甚至几十亿的时候,这个时候的损失就会大的吓人了。

3. 使用decimal

使用decimal第一步是引入这个包,decimal,在官方的描述中,这个包的功能描述如下:

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中任意精度定点的十进制数

注意:十进制库"只能"表示小数点后最多2^31位的数字。

小数点后2^31位数字,对于绝大多数的项目精度要求是足够的,简而言之,decimal可以解决我们绝大多数的浮点数精度计算场景。

对于上面精度丢失的case,当我们引入decimal包之后,我们可以得到正确的结果。

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
}

计算结果的精度没有丢失,计算结果正确。

4. decimal其他实用的场景

使用decimal的时候,切记浮点数计算所有数据的初始化必须通过decimal进行,否则还是会导致精度的丢失,为什么这么说呢,看看下面的例子你就明白了。

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就是因为100没有使用decimal进行初始化导致最后计算的精度被扩大了。正确的处理方式如下:

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 获取结果的整数部分

使用IntPart可以获取到浮点数计算结果的整数部分。

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 小数点后填充

使用IntPart可以对计算后的数据进行小数点位数的补零填充。

func TestDecimalThree(t *testing.T){
    a := 0.012
    b := 100
    x := decimal.NewFromFloat(a).Mul(decimal.NewFromInt(int64(b)))
    // 小数点后的位数填充, 0.012*100=1.2, 填充3位,因为已经有一位了,填充两个0, 1.200
    fmt.Println(x.StringFixed(3))
}

4.3 比较数字的大小

浮点数的比较decimal提供了一些比较有用的函数方法,这里列举了一部分。

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")
    // 是否是负数
    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 小结

decimal对于浮点数的计算提供了极大的便利性,让我们在使用浮点数进行大小计算的时候不用担心精度丢失的问题,尤其是对于金融行业,精度丢失造成资损就是很重大的生产事故了。

对decimal有一些基本的了解,当我们在工作中有场景需要使用到浮点数的计算的时候,可以直接使用decimal来帮助我们快速完善计算的逻辑。

到此这篇关于go语言中decimal的用法详解的文章就介绍到这了,更多相关go语言decimal用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • GO将mysql 中 decimal 数据类型映射到 protobuf的操作方法

    目录 protobuf中 float与double 1.如何在rpc中优雅取出dcemial类型 2.在rpc中 proto我们定义如下 2.1.proto - double 2.2.proto - float 3.在go-zero的sqlx中生成的model protobuf中 float与double 1.如何在rpc中优雅取出dcemial类型 例如我们在mysql中定义的一个字段如下: `discount` decimal(10,2) NOT NULL DEFAULT '0.00' CO

  • Golang 处理浮点数遇到的精度问题(使用decimal)

    目录 一.浮点数是什么? 1.指数方案 2.规范化指数形式 3.IEEE754标准 二.出现精度问题的情况 1.浮点数加减运算 2.float64与float32之间转换 3.int64和float64,int32和float32转换 4.float64位直接乘100 三.decimal解决精度问题 1.浮点数加减运算 2.float64与float32之间转换 3.float64位直接乘100 总结 一.浮点数是什么? 浮点数,是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意

  • go语言中decimal的用法详解

    目录 1. 精度丢失的case 2. decimal的应用场景 3. 使用decimal 4. decimal其他实用的场景 4.1 获取结果的整数部分 4.2 小数点后填充 4.3 比较数字的大小 5 小结 decimal是为了解决Golang中浮点数计算时精度丢失问题而生的一个库,使用decimal库我们可以避免在go中使用浮点数出现精度丢失的问题. github地址:https://github.com/shopspring/decimal 1. 精度丢失的case func TestFl

  • C语言中continue的用法详解

    目录 前言 continue 在while中的用法 continue 在for中的用法 continue 在剔除多余元素的用法 附:continue与break的区别 总结 前言 continue语句的作用是跳过本次循环体中余下尚未执行的语句,立即进行下一次的循环条件判定,可以理解为仅结束本次循环. 注意:continue语句并没有使整个循环终止. continue 在while中的用法 //continue 在while中的用法 #include<stdio.h> int main() {

  • C 语言中strstr函数实例详解

    C 语言中strstr函数实例详解 strstr函数 strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串.如果是,则该函数返回str2在str1中首次出现的地址:否则,返回NULL const char* strstr(const char* str1,const char* str2); char* strstr(char* str1,const char* str2); 库中实现的strstr #include <stdio.h> #include <

  • Go语言中sync.Cond使用详解

    目录 sync.Cond 可以用来干什么? 与 Sync.Mutex 的区别 sync.Cond 使用场景 sync.Cond sync.Cond 有哪些方法 NewCond 创建实例 Broadcast 广播唤醒所有 Signal 唤醒一个协程 Wait 等待 代码示例 sync.Cond 可以用来干什么? Golang 的 sync 包中的 Cond 实现了一种条件变量,可以使用多个 Reader 等待公共资源. 每个 Cond 都会关联一个 Lock ,当修改条件或者调用 Wait 方法,

  • C语言中的getchar()使用详解

    目录 前言 getchar困惑的点 缓冲区 缓冲区带来的问题 getchar工作原理 解决缓冲区带来的问题之清空缓存区 解决最初的困惑 总结 前言 近期我在重新学习C语言时候,我发现了一个严重的问题,getchar我居然不会用了....也不是说不会用,我发现了一个非常让我困惑想不明白的问题.可能我在第一次接触C语言时候,就没有把这个概念弄清楚吧,以至于现在会不明白. getchar困惑的点 我利用getchar函数输入了一串字符ABCD,然后把这串字符给到ch,然后紧接着我打印这个ch,然后我得

  • go语言中GoMock安装使用详解

    目录 安装 开始 使用参数匹配器 经验之谈 安装 GoMock是一个Go框架.它与内置的测试包整合得很好,并在单元测试时提供了灵活性.正如我们所知,对具有外部资源(数据库.网络和文件)或依赖关系的代码进行单元测试总是很麻烦. 为了使用GoMock,我们需要安装gomock包github.com/golang/mock/gomock和mockgen代码生成工具github.com/golang/mock/mockgen.使用这个命令行: go get github.com/golang/mock/

  • 关于C语言中E-R图的详解

    E-R  英文缩写为(Entity Relationship Diagram)也称实体-联系图. 提供了表示实体类型.属性和联系的方法,用来描述现实世界的概念模型. 下面就讲详解e-r图,如下: 从上面的的图可以看到一个完整的e-r图有四个部分: 1.矩形框,矩形表示实体型,矩形框内写明实体名: 2.椭圆框,椭圆表示实体的属性,并用无向边将其与相应的实体型连接起来: 3.菱形框,菱形表示实体型之间的联系,在菱形框内写明联系名, 4.联系线,实体与属性之间:实体与联系之间:联系与属性之间用直线相连

  • R语言中devtools的使用详解

    今天安装r语言devtools包,尝试很多种方法也不能决解,下面这个问题是改变镜像,然后就会可以安装了(3.4.2版本) Warning in install.packages : InternetOpenUrl failed: '无法解析服务器的名称或地址' Warning in install.packages : InternetOpenUrl failed: '不能连接到吊销服务器,或者未能获得最终响应.' Warning in install.packages : InternetOp

  • C语言中的malloc使用详解

    一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 与 malloc.h 的内容是完全一致的.) 功能:分配长度为num_bytes字节的内存块 说明:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL. 当内存不再使用时,应使用free()函数将内存块释放. 举例: #include<stdio.h&g

  • C语言中的const和free用法详解

    注意:C语言中的const和C++中的const是有区别的,而且在使用VS编译测试的时候.如果是C的话,请一定要建立一个后缀为C的文件,不要是CPP的文件.因为,两个编译器会有差别的. 一.C语言中的const比较常见的用法,const做常量 #include<stdio.h> #include<malloc.h> #include<string.h> /* C中的const用法(使用VS测试的时候,要注意建立一个C后缀的文件,因为C的编译器和C++的编译器还是有区别的

随机推荐