涉及金钱存储或计算操作时,你们一般都使用什么数据类型

2020-06-19 20:57:16 +08:00
 einsdisp

直接使用小数类型进行计算或存储(编程语言的 float 类型及数据库的 decimal 类型)

还是乘以 100,以分为单位,使用整数类型进行计算及数据库存储?

10520 次点击
所在节点    程序员
76 条回复
sagaxu
2020-06-20 20:10:12 +08:00
@cubecube double 到万亿这个数量级精度就不够了,比如 5 万亿加 0.1 分
joesonw
2020-06-20 22:05:15 +08:00
@sxd96 存储的就是不精确的啊. 你肉眼看到是 0.5, 实际数据并不是刚刚好 0.5 啊. 是 toString 的算法让你觉得存储的是精确的而已.
sxd96
2020-06-20 23:19:58 +08:00
@xuanbg

@joesonw

double 能不能确保存储进去和读取出来的值是一样的?

toString 将 double 解析成我肉眼看见的值,我在用 bigdecimal 计算的时候能不能确保转换后的值和 toString 的值是一样的?
知道个 overflow underflow 就看哪都是问题了?用脑子再多想两遍。
sxd96
2020-06-20 23:47:46 +08:00
@sxd96 自己更正一点。
double 的 frac 总共 52bit,精确表示数值加上前面的 sign 1bit 总共能精确表示正负 2^52 。
假设再加上可能有的 4 位小数,能精确表示的金额只有正负 2^48=281,474,976,710,656 以及后面的 4 位小数。适用场景大大受限。

事实上不做计算,仅做储存,能精确表示的范围也是相对固定的。但是我认为这个范围应该是够绝大多数公司撑到死了。
sxd96
2020-06-21 00:09:30 +08:00
@sxd96
脑子瓦特了,再更正一点。
如果要准确表示上面假设里说的 4 位小数,要 10bit 不是 4bit 。那么金额的整数部分就只有 2^42 = 4,398,046,511,104 。

在精确表示的范围内直接用 double 做算术运算也不会有问题的,也用不到什么 bigdecimal 。但是这个范围确实比我想当然的小了不少。4 个小数点存在的情况下,只能做到 4 万亿内的精确。

但是上面说的所谓 0.5 存着不是 0.5 就是开玩笑,double 的 1 那就是 1 。
用 decimal 肯定是第一反应也是最好的选择,当然没意见。但是看着这么多瞎说 double 溢出的,就很让人奇怪。
realpg
2020-06-21 10:22:11 +08:00
必须用整形,至于乘 100 、乘 10000 、乘 1000000,看项目精度要求
ysweics
2020-06-21 12:43:36 +08:00
金额还是统一 BigDecimal, 用别的搞法,出现问题,涉及到钱的一般都是大锅,望慎重
LnTrx
2020-06-21 14:03:18 +08:00
@sxd96
4 位小数应该是 14bit 吧?
只是存储问题当然有限,关键是实际计算的中间过程,容易出现防不胜防的错误判断、超出范围和舍入误差累积
参见: http://www.lahey.com/float.htm
ytmsdy
2020-06-21 21:23:35 +08:00
财务金额要是用 decimal 或者 float 的,一看就知道没有被四舍五入收拾过得!
财务上差一分钱会计和出纳都会拉着你查账查到半夜,而最后的结果往往都是四舍五入导致的!
所以!一定要用 int !一定要用 int !一定要用 int
ytmsdy
2020-06-21 21:25:13 +08:00
@3dwelcome 兄弟别在这里误导人!到时候因为四舍五入的问题查账查到半夜的不是你,而是停了你建议用 double 的兄弟!
datou
2020-06-22 05:12:22 +08:00
货币都是有定义最小单位的

为何要用浮点数?
luxinfl
2020-06-22 17:54:40 +08:00
自打做系统,金额类的用的一直是 bigdecimal 。但是我们数据库保存的是元,总感觉别扭
3dwelcome
2020-06-23 16:19:39 +08:00
@darrenfang 100.00000009 这种末尾本来就是计算误差,是随机数,你取出来的时候,直接 round 后断尾,精确度就完全没问题。
double 有效数是 14 位,不需要用全,保证前 12 位没有数字误差,就可以了。
IEEE 数据格式本来就是一个工具,在不同人手里,呈现的结果并不一样。代码是死的,人是活的,工具不趁手可以稍加改造。有坑多研究,总有绕过去的办法。
码农的天职不是无脑调用 API,而是解决各种棘手问题。
3dwelcome
2020-06-23 16:29:13 +08:00
@ytmsdy 四舍五入还不是因为计算精度误差。我说了 double 只是储存,如果计算累积精度不够,可以找高精度类来替代。
你们对 double 内部格式都没有真正理解,在没有小数位的情况下,整数数值储存部分 bit,和 INT 在二进制上表示,是一模一样的。
比如 double 存 1024 和 int 存 1024,内部就是一样的。只不过 double 里有指数位的存在,会对比特位进行 shift 操作。
mysunshinedreams
2020-06-28 17:33:02 +08:00
其实 String 就行,平时真要计算的时候,使用 joda Money 类。
CantSee
2020-06-30 15:54:44 +08:00
数据存储使用的金额单位是分,代码中金额操作使用 BigDecimal;

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/683167

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX