go货币计算时如何避免浮点数精度问题

 更新时间:2024年02月04日 16:45:10   作者:爱发白日梦的后端  
在开发的初始阶段,我们经常会遇到“浮点数精度”和“货币值表示”的问题,那么在golang中如何避免这一方面的问题呢,下面就跟随小编一起来学习一下吧

在开发的初始阶段,我们经常会遇到“浮点数精度”和“货币值表示”的问题。

那么,如何处理货币,如何存储和传递它们。

为什么是问题

Go语言中的标准浮点类型具有一定的精度(像其他任何语言一样),你不能在货币操作中使用它们。这里有一个最简单的例子:

var v1, v2 = 0.1, 0.2
fmt.Println(v1 + v2)
// 输出:0.30000000000000004

你可以计算你需要将一个值与另一个值相加多少次,才能在你的账户上获得额外的钱!但反过来也是一样 — 在这种情况下,你只是失去了你的钱。

这不仅在对你的钱进行数学运算时有问题,而且在不同系统或服务之间传递数据时也是有问题的。

下一个问题 — 传递你的钱

每次将你的钱从/到浮点数进行编组时,都会遇到与上述相同的问题,以及与编组器实现有关的其他问题 - json,xml,text等等...

另一个问题是四舍五入。如果你处理的是货币,你总会面临四舍五入的问题。你应该如何四舍五入你的货币值?例如 0.345 元,一般我们还是会四舍五入到 0.35 元?

我们的选择是什么

有一些特殊的类型可用于货币的表示和计算。

Go标准库有 big.Float 类型(来自 math/big 包,表示任意精度的浮点数)。与 float32float64 不同,它们具有固定的大小和精度,big.Float 允许你为数字和计算设置任意精度。

另一个不错的选择是 decimalgithub.com/shopspring/decimal

关于四舍五入:

  • 1.234 => 1.23
  • 1.235 => 1.24
  • 1.236 => 1.24

例如,shopspring/decimal 提供了适当舍入值的方法。

考虑的另一个好选择是使用货币单位。这样,你就从浮点数问题转移到整数,并将一切都作为整数计算。在这里唯一使用四舍五入的地方:传递结果值。

现在让我们讨论一下在传递货币时的选择。

  • 使用货币单位 — 我们将所有内容都传递为整数,这里没有浮点问题。只需控制值的限制,就可以了。
  • 将浮点数作为字符串传递。通常也是一个不错的选择 — 当你将浮点数作为字符串传递时,带有所需精度(特定小数位数)的字符串,当对方读取此字符串值并将其转换回浮点数时,你就是安全的。

简单的例子

你可以在 Go Playground 上尝试一下。

package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    a := 0.1
    b := 0.2
    c := decimal.NewFromFloat(a)
    d := decimal.NewFromFloat(b)
    fmt.Println(a, b, c.String(), d.String()) 
    fmt.Println(a + b) 
    fmt.Println(c.Add(d).String()) 
}

输出为:

0.1 0.2 0.1 0.2
0.30000000000000004
0.3

结论

处理货币时 — 使用 math/big 或一些与货币相关的库,比如 shopspring/decimal,或者只是使用货币单位,在这里不要使用浮点数。将货币作为字符串传递,或者在货币单位中传递,不要在这里使用浮点数。

其实还有一个小技巧:对于这些数值,我们可以使用:xxx * 10000 的方式,这样我们就可以保留其精度。10000 这个值可以在团队内协商。

到此这篇关于go货币计算时如何避免浮点数精度问题的文章就介绍到这了,更多相关go浮点数精度问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go  Zerolog使用入门教程

    Go  Zerolog使用入门教程

    Zerolog是一个高性能的Go日志库,通过零分配设计和结构化输出JSON格式,适用于高并发场景,它支持日志级别、采样、Context、Hook机制和同时输出控制台和日志文件等功能,本文介绍Go Zerolog使用入门教程,感兴趣的朋友跟随小编一起看看吧
    2026-03-03
  • Golang中的参数传递示例详解

    Golang中的参数传递示例详解

    参数传递是指在程序的传递过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程,下面这篇文章主要给大家介绍了关于Golang中参数传递的相关资料,需要的朋友可以参考下。
    2017-09-09
  • Go语言实现请求超时处理的方法总结

    Go语言实现请求超时处理的方法总结

    这篇文章主要为大家详细介绍了Go语言中实现请求的超时控制的方法,主要是通过timer和timerCtx来实现请求的超时控制,希望对大家有所帮助
    2023-05-05
  • 解析Go的Waitgroup和锁的问题

    解析Go的Waitgroup和锁的问题

    大家在学习go语言的时候,都知道go语言支持并发,使用 goroutine,使用关键字 go 即可,接下来通过本文给大家分享Go的Waitgroup和锁的问题,需要的朋友可以参考下
    2021-05-05
  • 基于go-cqhttp与Flask搭建定制机器人项目实战示例

    基于go-cqhttp与Flask搭建定制机器人项目实战示例

    这篇文章主要为大家介绍了基于go-cqhttp与Flask搭建定制机器人项目实战示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Go结合MQTT实现通信的示例代码

    Go结合MQTT实现通信的示例代码

    本文主要介绍了Go结合MQTT实现通信的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 一文详解Golang协程调度器scheduler

    一文详解Golang协程调度器scheduler

    这篇文章主要介绍了一文详解Golang协程调度器scheduler,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • Go使用Weighted实现资源管理

    Go使用Weighted实现资源管理

    这篇文章主要介绍了Go 语言中的 Weighted 并发原语,包括 Weighted 的基本使用方法、实现原理、使用注意事项等内容,感兴趣的小伙伴可以了解一下
    2023-06-06
  • golang json性能分析详解

    golang json性能分析详解

    json格式可以算我们日常最常用的序列化格式之一了,Go语言作为一个由Google开发,号称互联网的C语言的语言,自然也对JSON格式支持很好。下面这篇文章主要给大家详细分析介绍了golang json性能的相关资料,需要的朋友可以参考下。
    2018-02-02
  • Go语言中的range用法实例分析

    Go语言中的range用法实例分析

    这篇文章主要介绍了Go语言中的range用法,实例分析了range的功能与使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02

最新评论