新手问题 请问有谁能谈谈,在 migration 里 decimal 和 float 的具体区别呢?

QueXuQ · 2013年01月25日 · 最后由 xiaoronglv 回复于 2013年12月08日 · 6285 次阅读

我看基本涉及金额的,都是用 decimal 多。 如果我是一个数量问题呢,1,2,3,4,小数点也最多就 1.11,2.34 两位而已。 请问使用 decimal 和 float 有什么区别呢?

decimal 是用字符串存的,或者说是 10 进制,占用空间大,运算速度慢,精度可定制 float 是按照 ieee 标准存的,或者说是 2 进制,占用空间小,运算速度快,精度固定

只是 10 进制有限小数在 2 进制里可能是无限循环小数,存储空间的长度是固定的肯定要截断

#1 楼 @luikore 其实看了,觉得不是太理解,感觉是这样的话,好像 float 就没有存在的必要那样。 意思就是小数点尾数少的,数量小的,可以选择用 float,提高效率。 而太大的,和需要精度定制就选择 decimal 了?

1.4+1.7
=> 3.0999999999999996

如果是工程计算,这个结果精度是非常高的,但如果是算钱,这个结果是 3.1 才对:

require 'bigdecimal'
(BigDecimal('1.4') + BigDecimal('1.7')).to_s 'F'
=> "3.1"

#3 楼 @luikore

1.9.3p125 :001 > 1.4+1.7
 => 3.0999999999999996 
1.9.3p125 :002 > 2.1+3.2
 => 5.300000000000001 
1.9.3p125 :003 > 455.2+2333.1112
 => 2788.3111999999996 
1.9.3p125 :004 > 2.3*4
 => 9.2 
1.9.3p125 :005 > 2.55*4.2
 => 10.709999999999999 

试了一下,还真的是,这种精度要什么场合才用的上。。 那像一般需要精确的数值,还是用 decimal 好了吧。我存的只是商品数量,需要有小数。

#4 楼 @QueXuQ 整数的话用 int 就可以了,完全没这类问题

#5 楼 @luikore 不是整数,需要有小数。那是不是还是用 decimal 好了?

#6 楼 @QueXuQ 如果是需要显示".0", 最后格式化一下就好了... 如果商品的量是诸如千克之类的,有 3 位小数,改成用克 + 整数保存可能更方便

#7 楼 @luikore 不懂怎么是格式化? 比较混杂,有大量的整数,但是个别商品可能会分块出售,所以无论出入,都有可能出现数量是 3.55,2.5,之类的情况,但在两位小数内。。请问怎么整比较好?

#8 楼 @QueXuQ decimal 或者 乘 100 用整数都可以吧

我说的格式化是 '%.2f' % 1 #=> "1.00" 的意思,好像没什么关系...

#9 楼 @luikore 哦。貌似是个单纯的显示。 没想到 float 有那么大的学问,等我想想用什么方案处理这个问题好。谢谢。^_^

涉及到金额用 integer 到保存到分

我这编码规约只要是金额的全都用 bigdecimal,因为客户要求最大存 13 个 9

这个和数据库设计有关,Decimal 比 float 位数宽,记录的信息更多一些。

#11 楼 @knwang 然后现实在除 100 吗?

#14 楼 @QueXuQ 什么叫“现实”?

#15 楼 @knwang 显示。。。 就是说,输入 15.55 元,存入时乘 100 = 1555 读取时候,除于 100,显示 15.55

#16 楼 @QueXuQ 看你怎么显示了,换成元就是 / 100 了

#17 楼 @knwang 好。谢谢。似乎一般都使用 integer,要比使用 decimal 和 float 好。

#1 楼 @luikore 这个还真不是按照字符串存。字符串存浪费太大了。一般是八个位已存,第一位是 1 表示还有后续位,为 0 表示结束了。后面 7 个二进制位存数据。

#19 楼 @jimrokliu 用 BCD 存还是字符串存看数据库的实现吧,如果是 mongo 或者 sqlite 肯定是字符串

#20 楼 @luikore 是的,确实要看实现。可能有另外的实现。

#1 楼 @luikore

我忽然明白了 1.4 + 1.7 = 3.09999999999999999 了

谢谢

需要 登录 后方可回复, 如果你还没有账号请 注册新账号