不仅仅是 MySQL 特有的,浮点数和十进制类型之间的区别在于它们表示小数值的方式。浮点类型以二进制表示分数,它只能表示 {m*2^n | m, n Integers}值。像1/5这样的值不能精确表示(没有舍入错误)。十进制数同样也是有限的,但是表示像 {m*10^n | m, n Integers}这样的数字。Decimals 仍然不能表示1/3这样的数字,但在金融等许多常见领域,人们的期望是,某些小数总是可以表示而不会失去忠实度。由于十进制数可以表示类似于 $0.20(五分之一美元)的值,因此在这些情况下使用它更合适。
declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int
set @float =10.7
set @Decimal =10.7
set @Inetger=@Decimal
print @Inetger
这意味着 DB 引擎不需要 ASCII 到 int 的转换来将“数字”转换为 CPU 识别为数字的内容。没有舍入,没有转换错误,这是一个真正的数字,CPU 可以操纵。
对这个任意大小的整数的计算必须在软件中完成,因为没有硬件支持这种数字,但是这些库非常古老,并且高度优化,50年前就已经编写好支持 IBM 370 Fortran 任意精度浮点数据。它们仍然比使用 CPU 整数硬件完成的固定大小的整数代数或在 FPU 上完成的浮点运算慢得多。
就存储效率而言,由于浮点数的指数附加到每个浮点数上,并隐式指定小数点的位置,因此存储效率非常高,因此对于 DB 工作来说效率低下。在数据库中,你已经知道小数点在前面的位置,表中每一行有一个 DECIMAL 列的值,只需要查看小数点放置位置的1 & only 规范,存储在模式中作为 DECIMAL (M,D)的参数,作为 M 和 D 值的含义。
这里发现的关于各种应用程序使用哪种格式的许多评论是正确的,所以我不再赘述这一点。我之所以花时间在这里写这篇文章,是因为维护 MySQL 在线文档链接的人根本不理解上面的任何内容,在经过一轮又一轮越来越令人沮丧的尝试向他们解释之后,我放弃了。他们对所写内容的理解是多么的不足,一个很好的迹象就是他们对主题的表述非常混乱,几乎无法理解。
MySQL 允许非标准语法: FLOAT (M,D)或 REAL (M,D)或 DOULEPRECISION (M,D)。在这里,“(M,D)”意味着比值可以存储多达 M 位的总数,其中 D 位可以在小数点后面。例如,定义为 FLOAT (7,4)的列在显示时类似于 -999.9999。MySQL 在存储值时执行舍入,因此如果将999.00009插入到 FLOAT (7,4)列中,大致结果为999.0001。
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+-------+------+
| i | a | b |
+------+-------+------+
| 6 | -51.4 | 0 |
+------+-------+------+
1 row in set (0.00 sec)
相反,要获得数字相同的行,测试应该找到公差值内的差异:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) <= 0.0001;
+------+------+------+
| i | a | b |
+------+------+------+
| 1 | 21.4 | 21.4 |
| 2 | 76.8 | 76.8 |
| 3 | 7.4 | 7.4 |
| 4 | 15.4 | 15.4 |
| 5 | 7.2 | 7.2 |
+------+------+------+
5 rows in set (0.03 sec)
浮点值取决于平台或实现依赖关系:
CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0));
INSERT INTO t1 VALUES('1e+52','-1e+52');
SELECT * FROM t1;