MySQL 中使用浮点数和定点数来表示小数,其中浮点类型有两种,单精度浮点数FLOAT和双精度浮点数DOUBLE;定点类型只有一种就是 DECIMAL。
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
FLOAT | 4字节 | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8字节 | (-1.797 693 134 862 315 7 E+308,-2.225073858507 2014E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对decimal(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
浮点类型和定点类型都可以用(M, D)来表示,其中M表示总共的位数;D表示小数的位数。
浮点数类型FLOAT 和 DOUBLE的取值范围为 M(1~255)和 D(1~30,且不能大于 M-2),在未指定时默认会按照实际的精度(由计算机硬件和操作系统决定)保存。
定点数类型DECIMAL的取值范围是 M(0~65)和 D(0~30),并且0 <= D <= M <= 65。
浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的范围;缺点是会引起精度问题,所以在使用浮点数时需要注意,并尽量避免做浮点数比较。
FLOAT、DOUBLE与DECIMAL的区别
FLOAT单精度浮点数占 4 个字节,1个字节占8位,所以FLOAT存储浮点数用32位二进制进行描述。
DOUBLE双精度浮点数占 8 个字节,所以DOUBLE存储浮点数用64位二进制进行描述。
根据ieee二进制浮点数算术标准:
FLOAT单精度小数部分只能精确到后面6位,加上小数点前的一位,即有效数字为7位。
DOUBLE双精度小数部分能精确到小数点后的15位,加上小数点前的一位,有效位数为16位。
因此DOUBLE存储浮点数的精度更高,这里的精度主要取决于小数点后边位数的长度,越长越精确。但是,在程序中一般来说,cpu处理单精度浮点数的速度比处理双精度浮点数快,因为DOUBLE尾数比FLOAT的尾数多, 所以计算起来必然是有开销的。
虽然DOUBLE比FLOAT精度高一些,但两者存储的都是近似值,并不精确。而DECIMAL是精确存储,它是以字符串形式保存的精确数值,所以适合金额、价格等对精度要求较高的财务类型的数据。
CREATE TABLE test1(a FLOAT(10,2),b DOUBLE(10,2),c DECIMAL(10,2));
DESC test1;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a | float(10,2) | YES | | NULL | |
| b | double(10,2) | YES | | NULL | |
| c | decimal(10,2) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
INSERT INTO test1(a,b,c) VALUES(12.34, 12.34,12.34);
SELECT * FROM test1;
+-------+-------+-------+
| a | b | c |
+-------+-------+-------+
| 12.34 | 12.34 | 12.34 |
+-------+-------+-------+
#不论是定点还是浮点类型,如果存储的小数位数超出指定长度,则会四舍五入进行保存
INSERT INTO test1(a,b,c) VALUES(123.456, 123.456,123.456);
SELECT * FROM test1;
+--------+--------+--------+
| a | b | c |
+--------+--------+--------+
| 12.34 | 12.34 | 12.34 |
| 123.46 | 123.46 | 123.46 |
+--------+--------+--------+
#不论是定点还是浮点类型,如果存储的小数位数不足会自动补足
INSERT INTO test1(a,b,c) VALUES(12345.6, 12345.6,12345.6);
SELECT * FROM test1;
+----------+----------+----------+
| a | b | c |
+----------+----------+----------+
| 12.34 | 12.34 | 12.34 |
| 123.46 | 123.46 | 123.46 |
| 12345.60 | 12345.60 | 12345.60 |
+----------+----------+----------+
#浮点类型是近似存储,而定点类型是精确存储
INSERT INTO test1(a,b,c) VALUES(1234567.21, 1234567.21,1234567.21);
SELECT * FROM test1;
+------------+------------+------------+
| a | b | c |
+------------+------------+------------+
| 12.34 | 12.34 | 12.34 |
| 123.46 | 123.46 | 123.46 |
| 12345.60 | 12345.60 | 12345.60 |
| 1234567.25 | 1234567.21 | 1234567.21 |
+------------+------------+------------+
#浮点类型在计算时可能会造成精度损失
CREATE TABLE test2(a1 FLOAT,a2 FLOAT,b1 DOUBLE,b2 DOUBLE,c1 DECIMAL,c2 DECIMAL);
DESC test2;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a1 | float | YES | | NULL | |
| a2 | float | YES | | NULL | |
| b1 | double | YES | | NULL | |
| b2 | double | YES | | NULL | |
| c1 | decimal(10,0) | YES | | NULL | |
| c2 | decimal(10,0) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
INSERT INTO test2 VALUES (3.3,4.4,3.3,4.4,3.3,4.4);
SELECT * FROM test2;
+------+------+------+------+------+------+
| a1 | a2 | b1 | b2 | c1 | c2 |
+------+------+------+------+------+------+
| 3.3 | 4.4 | 3.3 | 4.4 | 3 | 4 |
+------+------+------+------+------+------+
SELECT a2-a1,b2-b1,c2-c1 FROM test2;
+--------------------+--------------------+-------+
| a2-a1 | b2-b1 | c2-c1 |
+--------------------+--------------------+-------+
| 1.1000001430511475 | 1.1000000000000005 | 1 |
+--------------------+--------------------+-------+
如何选择
当需要存储的小数对精度要求不高时,可以选择FLOAT单精度浮点型,可以节省内存空间,提高计算速度。
当需要进行高速数学计算、科学计算、卫星定位计算等对精度要求较高时,可以选择DOUBLE双精度浮点型。
当需要进行精确计算,如工资结算、转账打款等财务类型的数据,可以选择DECIMAL定点型。