![]() | 1 ferock PRO 分为单位,相应国家法规 |
![]() | 3 zlhsvc 191 天前 计算根据精度要求统一转成整形来计算,存储正常是分 |
![]() | 4 japeth 191 天前 第一种 |
5 w568w 191 天前 ![]() 第二种用法也不应该用 math/big ,那还是二进制的。而是应该用 Decimal ,比如: https://pkg.go.dev/github.com/shopspring/decimal 金额计算最重要的应该是 尽可能地延后计算(尤其是涉及乘除法的)来最大化避免误差。某些时候表达式(例如字符串 "10.0/3*3")可能是交换数据时更好的表示方式。 |
6 kkkwar 191 天前 正常用第一种,分;如果无奈必须要用第二种,用 shopspring/decimal 库 |
![]() | 7 justseemore 191 天前 元*1e6 存 bigint |
![]() | 8 NewYear 191 天前 最早的时候用 vb 实现的是,先转换为整数,再计算,算完再转为小数。 另外需要看场景,往往和钱有关系的系统,通常也和财务有关系,和财务有关系的通常和“成本核算”有关系。 此时,用“分”为单位反而不适合,因为涉及“成本”的计算,就要很多位小数了。 说回来,如果只是涉及“钱”,那未来也可能有多币种问题,还是绕不开多位小数。 所以为什么不一劳永逸呢。 |
![]() | 9 v1 191 天前 分三个字段,整数(bigint)、小数(bigint)、小数位数(int) |
![]() | 10 sardina 191 天前 上家公司数据库里存的是字符串,计算的话用了 decimal 库,小数点后保留 8 位,计算完后转字符串后存到数据库 |
![]() | 11 kuanat 191 天前 ![]() 这是个业务或者说工程问题,不全是技术问题。因为不像 Java 用 BigDecimal 比较多,Go 这边没有习惯性做法,所以主要靠约定,剩下的是如何执行。无论哪种语言,计算这类纯技术问题都是小事,与业务结合的部分才是大事。 我这里说几个技术人员可能不太熟悉的业务需求或者是需要注意的点: - 最理想的是用 Go 自定义数据结构,在数据结构上实现相应的运算方法。这样可以避免代码上的出错。这里比较关键的点是,计算过程肯定是高精度/整型(对应 BigDecimal ),同时一定要支持 split 操作,主要是处理类似 1 拆成 0.33+0.33+0.34 的业务需求,这种在会计、税务场景很常见。 - 根据全流程数据交换的环节来定义精度和数据格式。一般推荐的是比常见货币最小单位更精确一点,或者支持自定义。传递过程中使用字符串,做好格式转换。说到底还是靠约定,为了方便执行可以独立成库强制所有上下游都使用特定实现。 - 有需要的话提前考虑多币种支持,比如订单系统如果可以支持多币种,数据库和业务逻辑都要做 schema 调整。通常的业务需求来说,多币种就是多账本,如果最初设计成单账本后期修改会很痛苦。 - 推荐使用 event driven 架构来做 cqrs ,即用事务的方式持久化变动,实时状态由历史计算推导得出。类似银行卡只记录进出,余额是算出来的。好处一方面能和通常的消息队列架构方便对接,另一方面整个业务的可靠性、灾难恢复都好做。有 olap 需求也容易改造。 |
![]() | 12 guiyumin 191 天前 以最小单位存储 比如日元就没有分 美元有分 人民币有分 |
![]() | 13 pike0002 191 天前 minor unit |
14 futuretech6 191 天前 自己做一个指定 decimal 的定点数类吧 |
![]() | 15 zhangfeiwudi 191 天前 我有个问题,哪怕用分为单位算 如果除完之后 是 6666.6666666 这到底是直接舍弃小数点后面的 还是进一位? |
![]() | 16 Desdemor 191 天前 用的 5 楼的那个库 |
![]() | 17 v1 191 天前 @zhangfeiwudi 非金融行业的看领导决定咯,满五进一还是直接舍弃 |
![]() | 18 cyrivlclth 191 天前 @zhangfeiwudi 10 分分成 3 份,那就是 3+3+4 ,最后一份是差值出来的。至于用 3 还是 4 ,要业务方来决定 |
![]() | 19 me1onsoda 191 天前 @zhangfeiwudi 用分计算的目的就是为了方便直接舍弃 |
![]() | 20 adoal 191 天前 衍生问题:写 web API 时,JSON 里表示金额用什么类型? |
![]() | 22 realpg PRO 不是特殊金融行业 一律分 金融行业也争取用小数点后八位 int64 |
23 ALongRanger 191 天前 ![]() 我的回答可能和具体语言无关。 1. 建议采用对应货币最小单位作为存储,主要是为了避免在计算和存储过程中产生精度损失导致资损; 2. 不管是 java 还是 go ,请编码统一的金额处理工具包,定义好金额结构和转换方法,避免直接使用基础结构例如整形,浮点来表示金额, 所有金额的表示直接使用定义好的金额结构。 整个项目内部统一采用,保证金额计算、转换的准确性。 3. 一个金额处理工具包应该考虑如下内容: 3.1. 要能够进行序列化和比较 3.2 要能存储币种和金额,要确保高精度和标准化 3.3 要能提供丰富的操作方法,包括加减乘除,需要自定义舍入和四舍五入; 3.4 要提供常用单位 getAmount()和获取最小单位金额的方法 getAmountMinorUnit() 3.5 确保结构的不可变性和安全性; 3.6 需要能够根据币种计算出最小单位,例如人民币就是分,日元就是元; 3.7 乘除支持舍入,默认使用四舍五入,但是支持其它舍入方式。 以上可以在跨境支付、金融应用等需要高精度、多币种支持的场景种安全有效的进行金额处理。 |
24 hwdq0012 191 天前 c#里用 decimal 类型,十进制浮点 |
![]() | 25 pkoukk 191 天前 https://pkg.go.dev/github.com/shopspring/decimal 用这个,它同时支持 MYSQL |
![]() | 26 pkoukk 191 天前 @zhangfeiwudi 业务决定,不同场景不同处理方式,可能都会有。 |
27 james122333 191 天前 via Android 在前公司用 math/big 并封装成一 struct 本来想用 decimal 但搞计算的用 math/big 就算了 理由是精度够高了 至于延后计算可能要另外找库或自己刻 没特别研究过 肯定是种专业的数学库 |
![]() | 28 ixcode 191 天前 bigint + decimal 加密货币小数点后 18 位都能算 |
29 sampeng 191 天前 so ?你要用毛吗?哈哈哈哈哈哈 |
![]() | 31 lesismal 191 天前 除了 blockchain 动辄多少个 0 的大范围数值,其他普通领域 int64 保平安足够了 |
32 mengzhuo 191 天前 某鹅某部门就是分为单位,int64 |
![]() | 34 cheng6563 191 天前 反正别出现浮点数就行了 |
35 KingHL 191 天前 这个有什么鸡毛讨论的,普通货币有用 2 的大聪明出来说说? |
36 james122333 191 天前 via Android |
![]() | 37 realpg PRO |
38 james122333 191 天前 via Android 细思了一下 其实这问题调用系统的 bc 命令也是个解法 还实现延后计算的问题 如果有 golang 版做成 lib 的 bc 会更好 |
40 james122333 191 天前 via Android 事实上 bc 是种语言 也有 function 可以用 任意精度到 2147483647 位 https://zh.m.wikipedia.org/zh-cn/Bc%E8%AF%AD%E 命令行 cp 值真的太高 |
41 crackidz 191 天前 第一种,如果要用第二种,一定要用 decimal |
43 cslive 190 天前 @zhangfeiwudi 有个算法叫银行家算法,6666.6666666 这到底是直接舍弃小数点后面的 还是进一位 |
45 back0893 190 天前 啊?只用 rmb 就分呗 |
46 arsenal4 190 天前 上面有人提到银行家算法。我想请教一下,银行家算法是通用做法吗?还是一种可选项?曾经被一个空降的 CTO 无情嘲讽,原话是『我从没见过一个电商平台使用四舍五入』 |
47 lvlongxiang199 190 天前 @kk2syc 那你这咋进行加减乘除的计算呢 ? |
![]() | 48 madku 190 天前 decimal |