直接使用小数类型进行计算或存储(编程语言的 float 类型及数据库的 decimal 类型)
还是乘以 100,以分为单位,使用整数类型进行计算及数据库存储?
1
wwti9 2020-06-19 20:59:36 +08:00
乘以 100
|
2
yulitian888 2020-06-19 20:59:58 +08:00
一万倍,长整型
|
3
wujieyuan 2020-06-19 21:02:50 +08:00
我见过好多用 double 或者 String 的, 但是我觉得用分做单位,整数型最稳,除专业金融领域, 分单位足够用了
|
4
cigarzh 2020-06-19 21:09:51 +08:00 1
BigDecimal 一把梭,不要想自己搞什么花花肠子
|
5
xuanbg 2020-06-19 21:17:26 +08:00
金额使用 BigDecimal,金融行业 4 位小数,非金融 2 位小数。单价、利率什么的也用 BigDecimal,具体几位小数看需求。
|
6
ackoly 2020-06-19 21:18:54 +08:00 via iPhone
用分一定要小心,见过本来要配置 100 元的,没加两个 00,变成 1 块。
|
7
xuanbg 2020-06-19 21:19:19 +08:00
double 、float 仅用于科学计算,用在业务系统里面就是搞笑。
|
8
xuanbg 2020-06-19 21:21:36 +08:00
用 string 就更搞笑了,完全是治标不治本。
|
9
billlee 2020-06-19 21:52:50 +08:00
不能一概而论,算加减法用定点数没有问题,但利息什么的要用乘法的时候,还是得用浮点数
|
10
vanillaxxx 2020-06-19 22:00:17 +08:00 via iPhone
bigdecimal
|
11
pinkSlime 2020-06-19 22:01:07 +08:00
用 double 做清结算之类的 没被人砍死吗?
还是想留后门自己薅羊毛 |
12
Aruforce 2020-06-19 22:02:13 +08:00 via Android
存储用分…计算的话最后用减……
|
13
dswyzx 2020-06-19 22:37:57 +08:00
数据库落库 decimal
业务里各种千奇百怪的要求,四位小数,两位小数,不要小数.都要涉及取整操作.真烦 |
14
3dwelcome 2020-06-19 22:45:02 +08:00 via Android
我要给 double 正名!按说精度也有 14 位,怎么就不能当存储类型了?
统计有误差,是因为有计算中有误差会逐渐累计!你把误差去掉,或者用高精度大数类型替代一下就可以。 光保存是没问题的。 |
15
dodo2012 2020-06-19 22:48:59 +08:00
decimal,,,
|
16
liprais 2020-06-19 22:55:44 +08:00 via iPhone
不用 decimal 早晚有问题
|
17
zjsxwc 2020-06-19 23:07:33 +08:00 via Android
两位小数,decimal 逃
|
18
Mac 2020-06-19 23:22:26 +08:00
decimal
|
20
Sharuru 2020-06-19 23:42:33 +08:00 via Android
BigDecimal 一把梭,多币种清算业务毫无压力。
|
21
xingheng 2020-06-19 23:44:29 +08:00
万万没想到,居然还有这么多人写的系统用浮点类型,惊到了
|
24
zjsxwc 2020-06-20 02:08:08 +08:00 via Android 1
@xuanbg #8 原文:“用 string 就更搞笑了,完全是治标不治本。”
回复: 我倒觉得如果不用 decimal 而用 ` 两位小数的 string `或者 `乘以 100 的 integer `,貌似也都可以,因为好像也不会碰到无脑 double 浮点数运算的误差问题。 |
26
susunus 2020-06-20 07:59:26 +08:00 via iPhone
老实说目前用的就是 Double 存储的,计算的时候,用用 BigDecimal 包裹,处理了下精度问题,那位老哥帮忙科普下,这样有啥风险
|
28
reself 2020-06-20 08:18:41 +08:00 via Android 1
@susunus 浮点数只能表示数轴上的离散点,计算结果只能近似到最近的点,除非刚好能用 2 进制表示,例如 0.5,否则都是近似值。数轴上的点数量是无穷的,用有穷的浮点数来做计算,有偏差的概非常大。所以浮点数只能用在能容忍偏差的场景,比如图形绘制。除了数值偏差,浮点数还有众所周知的不能用==判定相等的特性。
|
29
LukeEuler 2020-06-20 08:46:47 +08:00
小数字用 decimal,大数字用 string,bytes 之类的,自己设计运算方法。
存储的和传输内容都是整数,只有显示时用 string 形式的浮点数。 |
30
mitu9527 2020-06-20 08:58:10 +08:00
参考 Money 模式,底层一般用 64 位的整型就可以了;如果长整型还不够用,那就考虑 GMP 吧。
|
31
darrenfang 2020-06-20 09:16:56 +08:00
@3dwelcome #14 以前写的代码用 double,突然发现数据库里面存的数据变成了 100.00000009,哈哈哈哈哈
|
35
des 2020-06-20 10:07:06 +08:00
并不需要转数值再计算,可以看一下这个 https://oi-wiki.org/math/bignum/
|
36
yadiman 2020-06-20 10:13:41 +08:00
某金融,13 位整形,minor unit,配合 decimal flag,然后转化成 major unit 。
比如,美金,decimal flag 就是 2,所以,100 minior unit = 1 USD major unit 越南盾,decima flag 就是 0,10000 minor unit 就是 10000 越南盾元。 通货膨胀,经常爆了。。。 |
37
PopRain 2020-06-20 10:38:31 +08:00
c# Decimal 值类型表示介于正 79,228,162,514,264,337,593,543,950,335 和负 79,228,162,514,264,337,593,543,950,335 之间的十进制数字。
sql server money -922,337,203,685,477.5808 到 922,337,203,685,477.5807 (对于 Informatica,为 -922,337,203,685,477.58 到 922,337,203,685,477.58 。Informatica 仅支持两位小数,而不是四位。) 我想不出来什么应用可以超出它的范围 |
38
PopRain 2020-06-20 10:40:49 +08:00
😓,楼上的通货膨胀没有考虑到,以百万为货币单位的货币是很容易爆。。。
|
40
U97F3 2020-06-20 11:01:07 +08:00 via Android
Numeric(19, 2)
|
41
PopRain 2020-06-20 12:30:42 +08:00
@mitu9527 用整数也有问题,小数点的位置问题,常用货币 1 JPY=0.009357 USD,还有一些以亿元为单位的货币
|
42
DOLLOR 2020-06-20 13:15:06 +08:00
|
43
Building 2020-06-20 13:24:41 +08:00 via iPhone
@xuanbg String 不能做四则运算......按你这个意思你是不是觉得计算机只要超过 UIntMax 的整数就没办法表示了?
|
44
rapiz 2020-06-20 14:00:05 +08:00 1
一帖显示出 v2 上有多少人基本功不过关
|
45
hantsy 2020-06-20 14:13:22 +08:00
用 Java 的话,有 Java Money 标准(JSR354),和 Java DateTime 一个时期的产品,可惜一直没进 JDK 。
但是这个项目已经很成熟,https://javamoney.github.io/ ,官方提供了 JPA 扩展,也就是说直接用关系数据库没问题的。 @cigarzh @xuanbg 遇到金融数据,自然想到 BigDecimal 当然是最基本的常识。但是 Money 还包括了相应 Currency 的处理,特别是国际化方面。 |
46
mitu9527 2020-06-20 15:04:57 +08:00
@PopRain 从数学角度看,不管你怎么处理总会存在误差,1/3 永远都除不尽,总是在某个位置要截断。我们要做的是把问题解决到可接受范围内,而不是完美解决。所以靠长整型和 Money 模式可以解决绝大多数问题,性能也还不错;如果业务真的要处理津巴布韦这种货币了,用 GMP,支持任意长度的整型,本质上是字符串,就是性能差。
|
47
PopRain 2020-06-20 15:15:21 +08:00
@mitu9527 我是支持用 Decimal 的,基本在业务范围内的问题都可以解决,而整数很多需要自己处理,遇到某些不熟悉的程序员,可能出现大问题,譬如上面说的 1 元=100
|
48
xuanbg 2020-06-20 15:50:35 +08:00
|
49
yuzo555 2020-06-20 16:06:17 +08:00
没研究,但是如果强行用 double 的话,我感觉,除了:
1.误差好像基本上都是小于 10^-7 级别 (0.0000001) 的误差,每次计算完后都按照要求精度 round 一下应该可以解决这个问题; 2.比较相等 == 的时候需要额外处理下。 还有哪些需要注意的吗。 |
50
mitu9527 2020-06-20 16:23:33 +08:00
@xuanbg 原谅 PHP 太 low,没有 BigDecimal,只能用 GMP 或者 BC Math 扩展。然后最懒的方式就是用现成的、实现 Money 模式的库,还可以搞定币种、最小金额单位和分配等问题。
|
51
everhythm 2020-06-20 16:26:23 +08:00
用 int,不同币种可以指定价格等级,类似 appstore
不然等着被疯狂薅 1 分钱羊毛 |
52
cubecube 2020-06-20 16:30:10 +08:00
@3dwelcome 其实我原来在银行的时候,非核心的外部系统,C 开发的,double 用来处理也没啥问题。基本上有效位数是够的。
|
53
chenuu 2020-06-20 17:53:25 +08:00 via Android
Long,经过我们系统的大概千亿级
|
54
zhuweiyou 2020-06-20 19:35:40 +08:00
运算还是存储,存储的话,什么都行。涉及运算要么用大数类,要么单位分 整数运算。
|
55
Vegetable 2020-06-20 19:40:08 +08:00
好奇为什么 Decimal 不是标准答案
|
56
celeron533 2020-06-20 19:44:17 +08:00
decimal
|
57
sxd96 2020-06-20 19:52:08 +08:00 via iPhone
不知道楼上在喷什么,人家说用 double 存储,存储有问题吗?计算的时候拿出来怎么样精确计算各有各的方法,谁都知道 double 直接算会出问题。
|
58
devinww 2020-06-20 19:59:11 +08:00
BigDecimal
|
60
sagaxu 2020-06-20 20:04:28 +08:00 via Android
int string 或者 double 都行,只要处理得当。但是最后你会发现,你重新发明了 decimal 的轮子
|
62
joesonw 2020-06-20 22:05:15 +08:00
@sxd96 存储的就是不精确的啊. 你肉眼看到是 0.5, 实际数据并不是刚刚好 0.5 啊. 是 toString 的算法让你觉得存储的是精确的而已.
|
63
sxd96 2020-06-20 23:19:58 +08:00 via iPhone
|
64
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 位小数。适用场景大大受限。 事实上不做计算,仅做储存,能精确表示的范围也是相对固定的。但是我认为这个范围应该是够绝大多数公司撑到死了。 |
65
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 溢出的,就很让人奇怪。 |
66
realpg 2020-06-21 10:22:11 +08:00
必须用整形,至于乘 100 、乘 10000 、乘 1000000,看项目精度要求
|
67
ysweics 2020-06-21 12:43:36 +08:00
金额还是统一 BigDecimal, 用别的搞法,出现问题,涉及到钱的一般都是大锅,望慎重
|
68
LnTrx 2020-06-21 14:03:18 +08:00
@sxd96
4 位小数应该是 14bit 吧? 只是存储问题当然有限,关键是实际计算的中间过程,容易出现防不胜防的错误判断、超出范围和舍入误差累积 参见: http://www.lahey.com/float.htm |
69
ytmsdy 2020-06-21 21:23:35 +08:00 via iPhone
财务金额要是用 decimal 或者 float 的,一看就知道没有被四舍五入收拾过得!
财务上差一分钱会计和出纳都会拉着你查账查到半夜,而最后的结果往往都是四舍五入导致的! 所以!一定要用 int !一定要用 int !一定要用 int |
70
ytmsdy 2020-06-21 21:25:13 +08:00 via iPhone
@3dwelcome 兄弟别在这里误导人!到时候因为四舍五入的问题查账查到半夜的不是你,而是停了你建议用 double 的兄弟!
|
71
datou 2020-06-22 05:12:22 +08:00
货币都是有定义最小单位的
为何要用浮点数? |
72
luxinfl 2020-06-22 17:54:40 +08:00
自打做系统,金额类的用的一直是 bigdecimal 。但是我们数据库保存的是元,总感觉别扭
|
73
3dwelcome 2020-06-23 16:19:39 +08:00
@darrenfang 100.00000009 这种末尾本来就是计算误差,是随机数,你取出来的时候,直接 round 后断尾,精确度就完全没问题。
double 有效数是 14 位,不需要用全,保证前 12 位没有数字误差,就可以了。 IEEE 数据格式本来就是一个工具,在不同人手里,呈现的结果并不一样。代码是死的,人是活的,工具不趁手可以稍加改造。有坑多研究,总有绕过去的办法。 码农的天职不是无脑调用 API,而是解决各种棘手问题。 |
74
3dwelcome 2020-06-23 16:29:13 +08:00
@ytmsdy 四舍五入还不是因为计算精度误差。我说了 double 只是储存,如果计算累积精度不够,可以找高精度类来替代。
你们对 double 内部格式都没有真正理解,在没有小数位的情况下,整数数值储存部分 bit,和 INT 在二进制上表示,是一模一样的。 比如 double 存 1024 和 int 存 1024,内部就是一样的。只不过 double 里有指数位的存在,会对比特位进行 shift 操作。 |
75
mysunshinedreams 2020-06-28 17:33:02 +08:00
其实 String 就行,平时真要计算的时候,使用 joda Money 类。
|
76
CantSee 2020-06-30 15:54:44 +08:00
数据存储使用的金额单位是分,代码中金额操作使用 BigDecimal;
|