mysql下float类型使用一些误差详解
单精度浮点数用4字节(32bit)表示浮点数
采用IEEE754标准的计算机浮点数,在内部是用二进制表示的
如:7.22用32位二进制是表示不下的。
所以就不精确了。
mysql中float数据类型的问题总结
对于单精度浮点数Float: 当数据范围在±131072(65536×2)以内的时候,float数据精度是正确的,但是超出这个范围的数据就不稳定,没有发现有相关的参数设置建议:将float改成double或者decimal,两者的差别是double是浮点计算,decimal是定点计算,会得到更精确的数据。
1.float类型
float列类型默认长度查不到结果,必须指定精度,
比如 num float, insert into table (num) values (0.12); select * from table where num=0.12的话,empty set。
mysql> create table tt
-> (
-> num float(9,3)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into tt(num)values(1234567.8);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
注:超出字段范围,无法插入
代码如下 复制代码
mysql> insert into tt(num)values(123456.8);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 123456.797 |
+------------+
1 row in set (0.00 sec)
注:小数位数不够,自动补齐,但是存在一个问题就是如上的近似值。
Query OK, 1 row affected (0.04 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
+------------+
3 rows in set (0.00 sec)
mysql> select * from tt where num=123456.867;
+------------+
| num |
+------------+
| 123456.867 |
+------------+
1 row in set (0.00 sec)
mysql> insert into tt(num)values(2.8);
Query OK, 1 row affected (0.04 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
| 2.800 |
+------------+
4 rows in set (0.00 sec)
mysql> select * from tt where num=2.8;
+-------+
| num |
+-------+
| 2.800 |
+-------+
1 row in set (0.00 sec)
mysql> insert into tt(num)values(2.888888);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------------+
| num |
+------------+
| 123456.797 |
| 123456.797 |
| 123456.867 |
| 2.800 |
| 2.889 |
+------------+
5 rows in set (0.00 sec)
注:小数位数超了,自动取近似值。
一、浮点数的概念及误差问题
浮点数是用来表示实数的一种方法,它用 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、要注意浮点数中一些特殊值的处理
注意事项
MYSQL 5.022中,
如果某个字段 f是float类型,那么在查询的时候,sql语句为:
select * from T where f = 2.2;
那么即使表中有2.2的数据也不能被查询到.
此时解决方法有2种:
1.将float改为double类型,不会出现这种问题.但是如果数据库中数据量庞大,或者修改量太大,则不适合这个方法.这个方法只适合设计数据库的初期阶段.
2.设置float的精度然后进行查询就可以了.
如果要精确到3位,则:select * from T where format(f,3) = format(2.2,3);
但是,精度不能超过6.否则出错.因为float类型最多允许精确到小数点后6位.
mysql下float类型使用一些误差详解的更多相关文章
- Mysql数据库日志类型查询与配置详解
在mysql中日志分为很多种,下面小编来给大家介绍Mysql数据库日志类型查询与使用,希望对各位同学会有所帮助 mysql常见的日志类型有五种:错误日志.二进制日志.查询日志.慢查日志和中继日志. 一 ...
- Mysql高手系列 - 第9篇:详解分组查询,mysql分组有大坑!
这是Mysql系列第9篇. 环境:mysql5.7.25,cmd命令中进行演示. 本篇内容 分组查询语法 聚合函数 单字段分组 多字段分组 分组前筛选数据 分组后筛选数据 where和having的区 ...
- Delphi下利用WinIo模拟鼠标键盘详解 有参考价值
https://blog.csdn.net/fgrass_163/article/details/6365296 Delphi下利用WinIo模拟鼠标键盘详解 2011年04月26日 21:03:00 ...
- MYSQL服务器my.cnf配置文档详解
MYSQL服务器my.cnf配置文档详解 硬件:内存16G [client] port = 3306 socket = /data/3306/mysql.sock [mysql] no-auto-re ...
- mysql服务性能优化—my.cnf配置说明详解
MYSQL服务器my.cnf配置文档详解硬件:内存16G [client]port = 3306socket = /data/3306/mysql.sock [mysql]no-auto-rehash ...
- ambari-server启动出现ERROR main] DBAccessorImpl:106 - Error while creating database accessor java.lang.ClassNotFoundException:com.mysql.jdbc.Driver问题解决办法(图文详解)
不多说,直接上干货! 问题详情 ambari-server启动时,报如下的错误 问题分析 注:启动ambari访问前,请确保mysql驱动已经放置在/usr/share/Java内且名字是mysql- ...
- MySQL慢查询(二) - pt-query-digest详解慢查询日志 pt-query-digest 慢日志分析
随笔 - 66 文章 - 0 评论 - 19 MySQL慢查询(二) - pt-query-digest详解慢查询日志 一.简介 pt-query-digest是用于分析mysql慢查询的一个工具,它 ...
- Mysql高手系列 - 第8篇:详解排序和分页(order by & limit),及存在的坑
这是Mysql系列第8篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符号分开的表示可选其一. 本章内容 详解排序查询 详解limit limit存在的坑 分 ...
- Mysql高手系列 - 第14篇:详解事务
这是Mysql系列第14篇. 环境:mysql5.7.25,cmd命令中进行演示. 开发过程中,会经常用到数据库事务,所以本章非常重要. 本篇内容 什么是事务,它有什么用? 事务的几个特性 事务常见操 ...
随机推荐
- plan-6.17周末
喷完了自己,浑身舒爽. 搞个计划,最近要学东西,以提交博客为准,提交了才认为ok. 1.python的新书<<Fluent python>>不错,老的python资料已经满足不 ...
- 【C#日期系列(三)】--C#获取某个月的第一个星期几的年月日
需要获取某个月的第一个星期几的年月日 简单写了一个算法 #region 计算每月第一个星期1-7是各是几号 /// <summary> /// 计算每月第一个星期1-7是各是几号 /// ...
- Java Stream简介, 流的基本概念
在Javaor .net编程中, 我们经常见到"stream" 这个字眼. 我们大概知道这是个流的意思, 如果看完本文的话, 应该会有1个大概的概念. 一, Java中什么是St ...
- 红黑树(RB Tree)
看到一篇很好的文章 文章来源:http://www.360doc.com/content/15/0730/00/14359545_488262776.shtml 红黑树是一种高效的索引树,多于用关联数 ...
- C# 消除累计误差的倒计时
使用 C# 中自带的各种 timer 计时,都会有累计误差,以下代码实现了一种消除累计误差的方法,使得每次计时的误差,空值在 100 ms 以内(可以通过修改代码提升精度.) 对于精度要求在秒级别的简 ...
- latex常用命令
首行不缩进:在顶格的段落前面加上 \noindent 增加空格:\vspace{长度}:精确增加垂直距离,\hspace{长度} 与 \addvspace{长度}:增加高度长度的垂直空间 在公式的上. ...
- 基于python中staticmethod和classmethod的区别(详解)
例子 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 class A(object): def foo(self,x): print "executing foo ...
- FastReport.Net使用:[5]主从表
主从报表在日常生活中也很常用,譬如订单,班级学生报表等.下面以学生选课为例,以学生为主表,选课为从表做一学生选课报表. 绘制简单主从报表 1.绘制报表标题. 2.为数据区添加从表. ●可以直接右键数据 ...
- listView 一个 item更新
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 1,更新对应的 view 的内容 2,通过viewHolder去 设置 值 3,调用一次 ...
- Palindromic Tree 回文自动机-回文树 例题+讲解
回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同 ...