可以用个简单的例子来说明,
A 账号有 4 毛钱,B 账号有 6 毛钱,从 B 账号转到 A 账号一毛钱。
两个账号余额个是多少呢?
ᐅ irb
irb(main):001:0> a = 0.4
=> 0.4
irb(main):002:0> b = 0.6
=> 0.6
irb(main):003:0> a = a + 0.1
=> 0.5
irb(main):004:0> b = b- 0.1
=> 0.5
irb(main):005:0> a == b
=> true
看上去没问题,可是 A 账号有 7 毛钱,B 账号有 9 毛钱,再从 B 账号转到 A 账号一毛钱。
irb(main):012:0> a = 0.7
=> 0.7
irb(main):013:0> b = 0.9
=> 0.9
irb(main):014:0> a = a + 0.1
=> 0.7999999999999999
irb(main):015:0> b = b - 0.1
=> 0.8
irb(main):016:0> a == b
=> false
irb(main):017:0>
这是 IEEE 754 浮点储存的精度跟 rounding 问题,所有的语言都有这样的问题。
Java 里面有 float, 还有 double, double 的意思就是双倍精度,不过跟 integer 比较还是会有误差。
参考: http://ruby-china.org/topics/6982 http://ruby-china.org/topics/7376
用 BigDecimal 是安全的,但是,太麻烦了,还是用分直接一点,计算结算全用分,仅显示的时候格式化为元。
楼主问的是 BigDecimal 和用整数以分为单位的对比。
楼上两位都在说 float,话说用 float 保存金额的程序员怎么可能过试用期嘛,居然还有人点喜欢。
不知道是不是和Money用 cents 有关 它的解释是 Represents monetary values as integers, in cents. This avoids floating point rounding errors.
#3 楼 @zj0713001 你可能会这么做
def price
self.price_in_cents / 100.0
end
但用 price 去计算是一定会发生的,如果是 Float,那么麻烦依然存在。所以,最终 Ruby 这边还是不得不去用 BigDecimal
好吧,我没仔细看原帖,我能想到的区别: 1,内存跟储存的区别,两者是否占有同样大小空间? 2,运算的效能,bigdecemal 是比 float 慢的,integer 比 float 要快的, 3,fixnum 在 ruby 里面是 inmutable,跟 symbol 一样,所有的 5 都是同一个对象,BigDecimal 不是。 4,储存选择的灵活性跟通用性。
如果以上都不是考虑因素,那就无所谓了。
我们用的 postgres + decimal。Ruby 里直接用 BigDecimal。Ruby 2.1 开始可以用 decimal literal:0.1r
。
用 cents 保存的估计都不是金融系统(或是程序员懒惰),否则的话是没有办法处理一些金融方面的业务的,比如:http://en.wikipedia.org/wiki/Mill_%28currency%29
Mongo 没有 decimal?啊哈哈,估计也没太大关系,对数据精确度有要求的系统都不可能采用 Mongo 啊,LOL :trollface:
#11 楼 @hisea http://stackoverflow.com/questions/18934774/what-are-the-downsides-to-storing-money-values-as-cents-minor-units 等等还有一堆其他的讨论,浏览器历史记录没了...但是没有一个明显的讨论能得出“最佳实践”
我们这的新人培训之一就是,遇到金额的数据库字段类型一定要用 BigDecimal,因为它有方法直接进行“银行家舍入法”,并且要是进行其他的舍入方法也能很方便的实现
PS:19wu 的里面我本来提了个金额用 BigDecimal 来储存的 issue,结果没被采用
我查了下,可能是因为老版本的 MySQL(4.1 及以下)的 decimal data type 是将数据保存为 string:
In MySQL versions up to and including 4.1, DECIMAL columns are represented as strings
http://dev.mysql.com/doc/refman/4.1/en/storage-requirements.html
我公司的使用方式简单直接 所有商品最低价格都是元 所以不存在这么难过的讨论 我在其他地方使用分做最低单位 然后显示的时候用 helper 做的 format...就是这样...
#23 楼 @zj0713001 其实我们的定价也都是元... 支付宝的接口金额那块是 decimal 的字符串,不过财付通是分
为啥会出现分的方案让我很好奇,但是查了一些资料后没找到什么信息