您现在的位置是:首页 >  云笔记 >  开发笔记 >  文章详情

decimal,float和double的区别

onekbit@163.com   2019-03-04 17:17:17   8人已围观

         经常在开发过程中看见decimal,float和double这3种数据类型,都可以用来作为浮点数值的存储,今天就研究一下这3种类型之间的区别:

        float:

       float数值类型用于表示单精度浮点数值,含字节数为4,32bit,数值范围为-3.4E38~3.4E38(7个有效位)是近似存储,并不精确

        double:

       double数值类型用于表示双精度浮点数值,含字节数为8,64bit数值范围-1.7E308~1.7E308(15个有效位)是近似存储,并不精确

        decimal:

       定点型,128bit,不存在精度损失,常用于银行帐目计算。(28个有效位)精确存储,凡是跟钱相关的都建议使用 Decimal。


       我这里引用找到的mysql5.2中文手册中的一段描述:

FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]

小(单精度)浮点数。允许的值是-3.402823466E+38到-1.175494351E-38、0和1.175494351E-38到3.402823466E+38。这些是理论限制,基于IEEE标准。实际的范围根据硬件或操作系统的不同可能稍微小些。

M是小数纵位数,D是小数点后面的位数。如果M和D被省略,根据硬件允许的限制来保存值。单精度浮点数精确到大约7位小数位。

如果指定UNSIGNED,不允许负值。

使用浮点数可能会遇到意想不到的问题,因为在MySQL中的所有计算用双精度完成。参见A.5.7节,“解决与不匹配行有关的问题”。

· DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]

普通大小(双精度)浮点数。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、0和2.2250738585072014E-308到 1.7976931348623157E+308。这些是理论限制,基于IEEE标准。实际的范围根据硬件或操作系统的不同可能稍微小些。

M是小数总位数,D是小数点后面的位数。如果M和D被省略,根据硬件允许的限制来保存值。双精度浮点数精确到大约15位小数位。

如果指定UNSIGNED,不允许负值。

· DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL]

为DOUBLE的同义词。除了:如果SQL服务器模式包括REAL_AS_FLOAT选项,REAL是FLOAT的同义词而不是DOUBLE的同义词。

· FLOAT(p) [UNSIGNED] [ZEROFILL]

浮点数。p表示精度(以位数表示),但MySQL只使用该值来确定是否结果列的数据类型为FLOAT或DOUBLE。如果p为从0到24,数据类型变为没有M或D值的FLOAT。如果p为从25到53,数据类型变为没有M或D值的DOUBLE。结果列范围与本节前面描述的单精度FLOAT或双精度DOUBLE数据类型相同。

FLOAT(p)语法与ODBC兼容。

· DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]

压缩的“严格”定点数。M是小数位数(精度)的总数,D是小数点(标度)后面的位数。小数点和(负数)的‘-’符号不包括在M中。如果D是0,则值没有小数点或分数部分。DECIMAL整数最大位数(M)为65。支持的十进制数的最大位数(D)是30。如果D被省略, 默认是0。如果M被省略, 默认是10。

如果指定UNSIGNED,不允许负值。

所有DECIMAL列的基本计算(+,-,*,/)用65位精度完成。

· DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]

是DECIMAL的同义词。FIXED同义词适用于与其它服务器的兼容性。


上面已经从基础层面介绍了3种数据类型,那么我还有以下问题需要研究明确:

  1. 第一、 如何理解单精度和双精度? 
  2. 这两者的区别如果理解为“单精度是精确到小数点后一位,而双精度是精确到小数点后两位”,那就大错特错了。实际上由于float的有效位数是7位,double的有效位数是16位,因此单精度、双精度其实是指代这里的有效位数。如下图:


  3. 另外需要注意的是有效位数并不等于精确位数,纵然float可以表示到小数点后7位,但只有前6位是精确的,第7位很可能造成数据误差。而对于double来说只有前15位是精确的,第16位也很可能造成数据误差。

  4. 第二、精度损失如何产生?
  5.       关于float、double精度丢失的问题,实际上就是被扩展(类型转换)或截断(四舍五入)了,究其缘由是因为存取时标度不一致所导致的。在录入数据时若数据的标度与定义列数据类型时设置的标度不一致,则会导致存入时以近似的值来存储,这就造成了我们上面说到的精度丢失。
           那在什么情况下float、double的精度不会丢失呢?其实根据上面出问题的情况,我们可以想到当数据标度与类型标度一致时(录入数据的标度与定义列数据类型时设置的标度一致),就不会发生精度丢失。
           我们常选用decimal类型,小于等于其标度的数据都能被正确录入,不会发生精度丢失,因为其是将数据以字符串的形式来存进数据库的,这就保证了精确性。但并不是说decimal就不会发生精度丢失,因为它虽然不会发生精度扩展但却会发生精度截断,例如当录入数据的标度大于列数据类型设置的标度时,依然会发生四舍五入。

  6. 第三、其他待研究的问题


onekbit.com 经验笔记整理发布

分享到:


编辑发布时间:2019-03-04 17:17:17