展开全部

今天做实验,本来以前都已经做得差不多了的,可突然U盘一下子坏掉,计算机无法识62616964757a686964616fe78988e69d8331333335336537别,驱动重装没用,别人机器上也不能使用,看来是U盘自身出问题了。而更可怕的是,最近忙着整理材料,所以许多最新版本的材料和学习工作方面的资料都在U盘中,并且其中的许多老版本自己机器上早已删掉,怪只怪我太信任这块盘了。没办法,实验得重做,资料可能也得重新写重新找了......

然后就在做第二个实验结尾后意外地发现了MySQL数据类型中float的一个问题,现在帖出来请大家指点。百度中许多同仁也遇到了这个问题--传说中精典的浮点数精度问题。

原文如下:

一、浮点数的概念及误差问题:

浮点数是用来表示实数的一种方法,它用 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万亿!这个结果为什么与翟振兴例子中的差很多呢?原因是翟振兴的测试用表中对字段进行了限制,实际上显示的是mysql溢出后的值,而我这里给出的是计算机中实际的值,如果把测试表字段精度提高到24位或以上,得到的结果就相同了。

以上说明了因长度限制而造成的误差,但这还不是全部!采用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、要注意浮点数中一些特殊值的处理。

June,浮点数问题,很容易被忽视,可能具有一定的普遍性,也许应该发给其他技术人员,以免再出现这方面的问题。

-----Original Message-----

From: htang [mailto:htang@corp.netease.com]

Sent: Tuesday, September 26, 2006 6:29 PM

To: 翟振兴

Cc: LisaLan; 关宝军; 韦连友

Subject: RE: RE: mysql中float的问题

这个问题不是一个Bug,而是浮点数本身存在的局限。原因是计算机对浮点数的表示是 M * 2 的 N 次方,其中M是尾数,N是指数,在此转换过程中存在数据损失,因此浮点数(包括double类型)是不能精确表示所有实数的。出现的问题正是由误差和四舍五入造成的。

-----Original Message-----

From: 翟振兴 [mailto:zxzhai@corp.netease.com]

Sent: Tuesday, September 26, 2006 12:17 PM

To: htang

Cc: LisaLan; 关宝军; 韦连友

Subject: Re: RE: mysql中float的问题

Importance: High

老唐,您好!

昨天测试发现,当float数据类型超过131072时候,插入的数据会发现不稳定情况,测试过程如下:

mysql> desc test10;

+------------+---------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+------------+---------------+------+-----+---------+-------+

| floattest | float(12,2) | YES | | NULL | |

| doubletest | double(12,2) | YES | | NULL | |

| dectest | decimal(12,2) | YES | | NULL | |

+------------+---------------+------+-----+---------+-------+

mysql> insert into test10 values(131071,131071,131071);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

+-----------+------------+-----------+

1 row in set (0.00 sec)

mysql> insert into test10 values(131071.32,131071.32,131071.32);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

+-----------+------------+-----------+

2 rows in set (0.00 sec)

mysql> insert into test10 values(131071.68,131071.68,131071.68);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

+-----------+------------+-----------+

3 rows in set (0.01 sec)

mysql> insert into test10 values(131072,131072,131072);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

| 131072.00 | 131072.00 | 131072.00 |

+-----------+------------+-----------+

4 rows in set (0.00 sec)

mysql> insert into test10 values(131072.32,131072.32,131072.32);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

| 131072.00 | 131072.00 | 131072.00 |

| 131072.31 | 131072.32 | 131072.32 |

+-----------+------------+-----------+

5 rows in set (0.00 sec)

mysql> insert into test10 values(131072.68,131072.68,131072.68);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

| 131072.00 | 131072.00 | 131072.00 |

| 131072.31 | 131072.32 | 131072.32 |

| 131072.69 | 131072.68 | 131072.68 |

+-----------+------------+-----------+

6 rows in set (0.00 sec)

mysql> insert into test10 values(131072.66,131072.66,131072.66);

Query OK, 1 row affected (0.00 sec)

mysql> select * from test10;

+-----------+------------+-----------+

| floattest | doubletest | dectest |

+-----------+------------+-----------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

| 131072.00 | 131072.00 | 131072.00 |

| 131072.31 | 131072.32 | 131072.32 |

| 131072.69 | 131072.68 | 131072.68 |

| 131072.66 | 131072.66 | 131072.66 |

+-----------+------------+-----------+

mysql> insert into test10 values(1310720000000000000000.66,1310720000000000000000.66,1310720000000000000000.66);

Query OK, 1 row affected, 3 warnings (0.00 sec)

mysql> select * from test10;

+----------------+---------------+---------------+

| floattest | doubletest | dectest |

+----------------+---------------+---------------+

| 131071.00 | 131071.00 | 131071.00 |

| 131071.32 | 131071.32 | 131071.32 |

| 131071.68 | 131071.68 | 131071.68 |

| 131072.00 | 131072.00 | 131072.00 |

| 131072.31 | 131072.32 | 131072.32 |

| 131072.69 | 131072.68 | 131072.68 |

| 131072.66 | 131072.66 | 131072.66 |

| 10000000000.00 | 9999999999.99 | 9999999999.99 |

+----------------+---------------+---------------+

以上测试说明:

当insert的数据范围在+-131072(65536×2)以内的时候,float数据精度是正确的,但是超出这个范围的数据就不稳定,没有发现有相关的参数设置

建议:将float改成double或者decimal,两者的差别是double是浮点计算,decimal是定点计算,会得到更精确的数据。

已赞过

已踩过<

你对这个回答的评价是?

评论

收起

mysql中的float_mysql里float是什么东西相关推荐

  1. android float类型保留两位小数_你知道MySQL中Decimal类型和Float Double的区别吗?

    出处:cnblogs.com/panchanggui/p/10766607.html MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,flo ...

  2. mysql中还有窗口函数?这是什么东西?

    什么是窗口函数? 在mysql8.0的版本中,新增了一个窗口函数,用他可以实现很多新的查询方式.窗口函数类似于sun().count()那样的集合函数,但它并不会将多行查询结果合并为一行,而是将结果放 ...

  3. mysql''和null,mysql中NULL和null的区别

    接触php的web开发一段时间了,在进行数据库操作的时候经常会遇到一个问题,使得同一字段在页面显示时有3种类型NULL,null以及数字,当时的解决办法是将这一字段定义为varchar类型,在插入数据 ...

  4. mysql中整理设置__MySQL整理

    登录 命令:mysql -h [IP 地址/域名] -P [端口] -u [用户名] -p[密码] 端口默认是3306 mysql -hlocalhost -uroot -p 断开 exit; \q; ...

  5. decimal类型对象里面定义什么类型_MySQL中Decimal类型和Float Double的区别(详解)

    MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形 ...

  6. mysql中decimal与float_MySQL中的float和decimal类型有什么区别

    decimal 类型可以精确地表示非常大或非常精确的小数.大至 1028(正或负)以及有效位数多达 28 位的数字可以作为 decimal类型存储而不失其精确性.该类型对于必须避免舍入错误的应用程序( ...

  7. mysql中的double类型_MySQL中float、double、decimal三个浮点类型的区别与总结!

    作者:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,原创文章, B站技术分享 个人博客: cnblogs.com 前端h ...

  8. mysql double 存储_关于MYSQL中FLOAT和DOUBLE类型的存储-阿里云开发者社区

    关于MYSQL中FLOAT和DOUBLE类型的存储 重庆八怪 2016-04-12 844浏览量 简介: 关于MYSQL中FLOAT和DOUBLE类型的存储 其实在单精度和双精度浮点类型存储中其存储方 ...

  9. 关于MYSQL中FLOAT和DOUBLE类型的存储

    关于MYSQL中FLOAT和DOUBLE类型的存储 其实在单精度和双精度浮点类型存储中其存储方式和C/C++一致准守IEEE标准他们都是浮点型的,所谓的浮点型,是小数点的位置可变,其能够表示的范围比定 ...

最新文章

  1. 【Math】常见的几种最优化方法
  2. SQL--(MyBatis 实战)
  3. SDN,这一年都经历了什么
  4. 【网络安全】NFS服务安全加固
  5. Java中测长函数_Core Java测试题
  6. GNU make manual 翻译( 一百七十五)
  7. 谷歌提出“数据回波”榨干GPU空闲时间,训练速度提升3倍多
  8. curl txt批量_curl与wget高级用法
  9. php 防止url输入,php防止伪造数据从地址栏URL提交的方法
  10. 为什么php都用mysql,PHP MySQL为什么?
  11. mysql delete 数据之后 .MYD文件大小没有发生变化
  12. linux下main函数的返回值问题
  13. MFC异形窗口-多边形窗口-根据图片自定义窗口形状-CRgn
  14. 目前最全的动画名称中英对照表
  15. C语言基本——求圆的面积和周长
  16. 语音信号a率压缩算法c语言,基于OMAP5912平台的语音压缩算法实现
  17. html做秒表代码,利用JS实现一个可精确到10ms的秒表的制作(附代码)
  18. GB50207-2012 屋面工程质量验收规范 免费下载
  19. U8多组织协同方案、业务协同方案
  20. JavaScript——this关键字

热门文章

  1. Nature综述:植物与微生物组的相互作用:从群落装配到植物健康(下)
  2. 五彩进化树与热图更配-ggtree美颜进化树(宏基因组扩增子)
  3. R语言笔记5:控制结构
  4. 人体肠道细菌与自身细胞的比例究竟是多少?
  5. R语言将ggplot2对象转化为plotly对象并通过shiny将可视化结果在应用程序或者网页中显示出来
  6. R语言ggplot2包和lattice包可视化改变x轴和y轴的显示位置实战
  7. R语言构建xgboost模型、预测推理:输出预测概率、预测标签
  8. 机器学习数据预处理之缺失值:预测填充(回归模型填充、分类模型填充)
  9. Python打包工具Pyintealler打包py文件为windows exe文件过程及踩坑记录+实战例子
  10. python代码根据时间获取周数(week of the year)