设为首页 收藏本站
查看: 394|回复: 0

[经验分享] mysql中float、double数据类型的问题

[复制链接]

尚未签到

发表于 2016-10-18 08:18:21 | 显示全部楼层 |阅读模式
       总结:对于单精度浮点数Float:  当数据范围在+-131072(65536×2)以内的时候,float数据精度是正确的,但是超出这个范围的数据就不稳定,没有发现有相关的参数设置建议:将float改成double或者decimal,两者的差别是double是浮点计算,decimal是定点计算,会得到更精确的数据。
 
分析如下:
    一、浮点数的概念及误差问题:   
浮点数是用来表示实数的一种方法,它用 M(尾数) * B( 基数)的E(指数)次方来表示实数,相对于定点数来说,在长度一定的情况下,具有表示数据范围大的特点。但同时也存在误差问题,这就是著名的浮点数精度问题!   
 浮点数有多种实现方法,计算机中浮点数的实现大都遵从 IEEE754 标准,IEEE754 规定了单精度浮点数和双精度浮点数两种规格,单精度浮点数用4字节(32bit)表示浮点数,格式是:1位符号位 8位表示指数 23位表示尾数;双精度浮点数8字节(64bit)表示实数,格式是:1位符号位 11位表示指数 52位表示尾数。同时,IEEE754标准还对尾数的格式做了规范:d.dddddd...,小数点左面只有1位且不能为零,计算机内部是二进制,因此,尾数小数点左面部分总是1。显然,这个1可以省去,以提高尾数的精度。由上可知,单精度浮点数的尾数是用24bit表示的双精度浮点数的尾数是用53bit表示的,转换成十进制:
2^24 - 1 = 16777215           
2^53 - 1 = 9007199254740991     
由上可见,IEEE754单精度浮点数的有效数字二进制是24位,按十进制来说,是8位;双精度浮点数的有效数字二进制是53位,按十进制来说,是16 位。
显然,如果一个实数的有效数字超过8位,用单精度浮点数来表示的话,就会产生误差!同样,如果一个实数的有效数字超过16位,用双精度浮点数来表示,也会产生误差!
例如对于 1310720000000000000000.66 这个数,有效数字是24位,用单精度或双精度浮点数表示都会产生误差,只是程度不同:   
单精度浮点数: 1310720040000000000000.00   
双精度浮点数: 1310720000000000000000.00   
双精度差了 0.66 ,单精度差了近4万亿!以上说明了因长度限制而造成的误差,但这还不是全部!采用IEEE754标准的计算机浮点数,在内部是用二进制表示的,但在将一个十进制数转换为二进制浮点数时,也会造成误差,原因是不是所有的数都能转换成有限长度的二进制数。对于131072.32 这个数,其有效数字是8位,按理应该能用单精度浮点数准确表示,为什么会出现偏差呢?看一下这个数据二进制尾数就明白了 10000000000000000001010001......显然,其尾数超过了24bit,根据舍入规则,尾数只取 100000000000000000010100,结果就造成测试中遇到的“奇怪”现象!131072.68 用单精度浮点数表示变成 131072.69 ,原因与此类似。实际上有效数字小于8位的数,浮点数也不一定能精确表示,7.22这个数的尾数就无法用24bit二进制表示,当然在数据库中测试不会有问题(舍入以后还是7.22),但如果参与一些计算,误差积累后,就可能产生较大的偏差。
    二、mysql 和 oracle中的数值类型:   
问题是不是只有 mysql 存在呢?
显然不是,只要是符合IEEE754标准的浮点数实现,都存在相同的问题。     
mysql中的数值类型(不包括整型):   
 
IEEE754 浮点数: float(单精度),double或 real(双精度)
定点数: decimal 或 numeric    
oracle中的数值类型oracle  浮点数 :number (注意不指定精度)   
IEEE754浮点数 BINARY_FLOAT(单精度) ,BINARY_DOUBLE (双精度)
FLOAT,FLOAT(n) (ansi要求的数据类型)  定点数:number(p,s)    
如果在oracle中,用BINARY_FLOAT等来做测试,结果是一样的。     
因此,在数据库中,对于涉及货币或其他精度敏感的数据,应使用定点数来存储,对mysql来说是 decimal,对oracle来说就是number(p,s)。双精度浮点数,对于比较大的数据同样存在问题!
    三、编程中也存在浮点数问题:   
不光数据库中存在浮点数问题,编程中也同样存在,甚至可以说更值得引起注意!   
通过上面的介绍,浮点数的误差问题应该比较清楚了。如果在程序中做复杂的浮点数运算,误差还会进一步放大。因此,在程序设计中,如果用到浮点数,一定要意识到可能产生的误差问题。不仅如此,浮点数如果处理不好,还会导致程序BUG
看下面的语句:
if (x != y)
{
z = 1 / (x -y);
}
这个语句看起来没有问题,但如果是浮点数,就可能存在问题!
再看下面的语句会输出什么结果:
public class Test

public static void main(String[]args)
throws Exception
{
     System.out.print("7.22-7.0=" + (7.22f-7.0f)); 

}     
我们可能会想当然地认为输出结果应该是 0.22 ,实际结果却是 0.21999979 !      
因此,在编程中应尽量避免做浮点数的比较,否则可能会导致一些潜在的问题!     
除了这些,还应注意浮点数中的一些特殊值,如 NaN、+0、-0、+无穷、-无穷等,IEEE754虽然对此做了一些约定,但各具体实现、不同的硬件结构,也会有一些差异,如果不注意也会造成错误!
 
   
四、总结:   
从上面的分析,我们可以得出以下结论: 
1、浮点数存在误差问题;   
2、对货币等对精度敏感的数据,应该用定点数表示或存储;   
3编程中,如果用到浮点数,要特别注意误差问题,并尽量避免做浮点数比较;   
4要注意浮点数中一些特殊值的处理。   
  
 
本文来源于:http://blog.163.com/bbluesnow@126/blog/static/27784545201241610615201/

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-287690-1-1.html 上篇帖子: mysql 双向同步的键值冲突问题的解决方法 下篇帖子: MYSQL 优化器预处理阶段对子查询的优化
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表