7

问题描述

使用JPA映射一个float类型到数据库:

clipboard.png

然后存储129364.57,发现存储的结果是129365

clipboard.png

从上周就开始研究这个问题,查阅了各种资料,网上许多人都说是因为MySQL默认是保留六位有效数字,自己测试了一下也确实是这样。但是查询MYSQL官方文档,并没有找到依据。

MySQL官方文档:Float - MySQL

如果你看到了这篇文章,欢迎评论发表意见,让我们互相学习、进步。

结论

写的非常好的一篇文章,MySQL存储的各种尝试:MySQL数字类型int与tinyint、float与decimal如何选择

clipboard.png

JPA映射的Float默认的长度与小数点都是0

clipboard.png

这是测试的结果:float默认能精确到6位有效数字!

原理猜想

这是MySQL官方文档对floatdouble的描述:

官方文档并没有说MySQL是如何存储浮点数的,所以如果没有去读过其源代码,所有的博客都只是猜想。

clipboard.png

IEEE 754

目前大多数人认为MySQL内部是采用IEEE 754进行存储的,IEEE 754 - 维基百科

IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。

32位的单精度浮点数为例:

clipboard.png

与日常所说的科学计数法类似。

因为底数是有效数字,所以第一位肯定是1,所以这个1不进行存储,所以虽然是23位的底数,但是实际的底数位数其实是24位,含有一个隐含的1

双精度与此类似,一个符号位,指数位为11,尾数为52位,合计64位。

假设

假设是用MySQL是用IEEE 754标准存储的浮点数。

用单精度存储129364.57,其二进制为11111100101010100.1001000111101011100001010001111011

clipboard.png

正数:符号位为0

指数位为:00010000(十进制中的16)。

去掉第一个1,保留23位,底数为:11111001010101001001000

所以最后的结果是11111100101010100.1001000,转换为十进制为:129364.5625

clipboard.png

但是实际的MySQL存储后的结果为129365,所以猜想要么MySQL就是不是按IEEE 754存储的,要么就是按这个存储的但是内部为了数据库的性能等或其他的优化对数据进行了处理。

这里我这里更倾向于第二种,毕竟IEEE 754是一种国际标准,没有理由不遵守。


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。


« 上一篇
初识Angular
下一篇 »
Angular 表单