float、double精度可能丢失,decimal精度不会丢失,所以建议decimal来存储金额值。

在mysql中,我们用【小数数据类型(总长度,小数点长度)】来表示小数的总长度和小数点后面的长度。decimal(m,n)。n就是小数点后面的 数字个数。float(m,n)、double(m,n)含义差不多,都是定义长度和精度的。

下面看实操演示

1
2
3
4
5
-- total_price精度为小数点后六位<br>CREATE TABLE `order` (
  `id` bigint(11) NOT NULL,
  `total_price` float(10,6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;<br><br>-- insert<br>INSERT INTO `co_job`.`order`(`total_price`) VALUES (32.214);<br><br>-- query<br>SELECT * FROM `order` WHERE `id` = 1;
1
<br><br>

第一种情况: 存入小数精度不够6位

那么mysql会尽可能以近似的值存储,以保证精度。这里会出现精度丢失

 

第二种情况: 存入小数精度刚好6位

1
INSERT INTO `order`(`total_price`) VALUES (32.214412);SELECT * FROM `order` WHERE `id` = 2;<br><br>

 

 

仍然发生了精度丢失。

在查阅资料可知,单精度类型float和双精度类型double在计算机中存储的时候,由于计算机只能存储二进制,所以浮点型数据在存储的时候,必须转化成二进制。在计算机中,float型数据的存储格式为

 

 比如8.25用二进制表示可表示为1000.01,转成指数的形式1.00001*2^3,在计算机中

 

我们知道对于float类型的数据,只分配了32位的存储空间,对于double类型值分配了64位,但是并不是所有的实数都能转成32位或者64位的二进制形式,如果超过了,就会出现截断,这就是误差的来源。

比如131072.32转成二进制后的数据为:100000000000000000.0101000111101011100001010001111010111000010100011111… 这是一个无穷数,对于float类型,只能截取前32位进行存储,对于double只能截取前64位进行存储。所以 131072.32保存为float类型是存储形式为:01001000000000000000000000010100; 131072.32保存为double类型的格式为:0100000100000000000000000000001010001111010111000010100011110101

针对float情况,至少我们可以得出结论:

1.如果一个float型数据转成二进制后的第32位之后都是0,那么数据是准的

2.如果一个float型数据转成二进制后的第32位之后不全为0,则数据就会存在误差

 

第三种情况:存入小数精度大于6位

这种情况不必多说,一定会出现精度丢失。

 

 

 

参考资料:https://cloud.tencent.com/developer/article/1866266