【发布时间】:2011-07-06 05:40:05
【问题描述】:
在 MySQL 中使用 float 和 decimal 数据类型有什么不同?
我应该什么时候使用哪个?
【问题讨论】:
-
不要使用
FLOAT(m,n),它会导致两次舍入;同时,它没有任何用处。
标签: mysql
在 MySQL 中使用 float 和 decimal 数据类型有什么不同?
我应该什么时候使用哪个?
【问题讨论】:
FLOAT(m,n),它会导致两次舍入;同时,它没有任何用处。
标签: mysql
This 是我有这个疑问时发现的。
mysql> create table numbers (a decimal(10,2), b float);
mysql> insert into numbers values (100, 100);
mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G
*************************** 1. row ***************************
@a := (a/3): 33.333333333
@b := (b/3): 33.333333333333
@a + @a + @a: 99.999999999000000000000000000000
@b + @b + @b: 100
在这种情况下,小数点做了应该做的事情,它 截断其余部分,从而丢失 1/3 部分。
所以对于总和,小数更好,但对于除法,浮点数是 更好,在某种程度上,当然。我的意思是,使用 DECIMAL 不会给出 无论如何,您都是“防故障算术”。
希望这会有所帮助。
【讨论】:
@a 不是给 99.999999999000000000000000000000 十进制吗?这在技术上是正确的。
大多数环境中的“浮点数”是二进制浮点类型。它可以准确地存储以 2 为底的值(到某个点),但不能准确地存储许多以 10 为底的(十进制)值。浮点数最适合科学计算。它们不适用于大多数面向业务的数学,并且不恰当地使用浮点数会咬你。许多十进制值不能以 base-2 精确表示。例如,0.1 不能,因此您会看到像 1.0 - 0.1 = 0.8999999 这样的奇怪结果。
小数存储以 10 为底的数字。 Decimal 是大多数商业数学的好类型(但任何内置的“货币”类型都更适合财务计算),其中值的范围超出了整数类型提供的范围,并且需要小数值。顾名思义,小数是为以 10 为底的数字设计的 - 它们可以准确地存储十进制值(同样,到某个点)。
【讨论】:
MySQL 最近改变了他们存储DECIMAL type 的方式。过去,他们为每个数字存储字符(或 nybble),包括数字的 ASCII(或 nybble)表示 - 与 - 二进制补码整数或其某种导数。
当前 DECIMAL 的存储格式是一系列 1、2、3 或 4 字节整数,它们的位连接起来创建一个带有隐含小数点的二进制补码,由您定义,并存储在 DB 架构中当您声明该列并指定它的 DECIMAL 大小和小数点位置时。
例如,如果您采用 32 位 int,则可以存储 0 到 4,294,967,295 之间的任何数字。那只能可靠地覆盖 999,999,999,所以如果你扔掉 2 位并使用 (1
MySQL 在线文档中使用的示例使用 DECIMAL(18,9) 作为示例。这是隐含小数点前 9 位和后 9 位,如上所述,需要以下存储。
作为 18 个 8 位字符: 144位
作为 18 个 4 位半字节: 72位
作为 2 个 32 位整数: 64位
目前 DECIMAL 最多支持 65 位,如 DECIMAL(M,D),其中 M 允许的最大值为 65,D 允许的最大值为 30。
为了不一次需要 9 个数字的块,小于 32 位的整数用于添加使用 1,2 和 3 字节整数的数字。由于某种违反逻辑的原因,使用了有符号整数而不是无符号整数,这样做,1 位被丢弃,从而产生以下存储能力。对于 1,2 和 4 字节的整数,丢失的位无关紧要,但对于 3 字节的整数,这将是一场灾难,因为由于单个位的丢失,整个数字都会丢失。
使用 7 位整数: 0 - 99
使用 15 位整数: 0 - 9,999
使用 23 位整数: 0 - 999,999 (0 - 9,999,999,24 位整数)
1,2,3 和 4 字节整数连接在一起形成一个“位池” DECIMAL 用于将数字精确地表示为二进制补码整数。不存储小数点,这是隐含的。
这意味着 DB 引擎不需要将 ASCII 转换为 int 即可将“数字”转换为 CPU 识别为数字的东西。没有四舍五入,没有转换错误,这是 CPU 可以操纵的实数。
这个任意大整数的计算必须在软件中完成,因为这种数字没有硬件支持,但是这些库非常古老且经过高度优化,50 年前就已编写以支持 IBM 370 Fortran 任意精度浮点数据。它们仍然比使用 CPU 整数硬件完成的固定大小的整数代数或在 FPU 上完成的浮点计算慢很多。
在存储效率方面,因为浮点数的指数附加到每个浮点数,隐式指定小数点的位置,它是大量冗余的,因此对于数据库工作效率低下。在数据库中,您已经知道小数点在哪里,并且表中具有 DECIMAL 列值的每一行只需要查看 1 & only 指定该小数点的放置位置、存储位置在模式中作为 DECIMAL(M,D) 的参数作为 M 和 D 值的含义。
这里找到的许多关于将哪种格式用于各种应用程序的注释都是正确的,所以我不会强调这一点。我花时间在这里写这篇文章是因为维护链接的 MySQL 在线文档的人不了解上述任何内容,并且在向他们解释它的尝试越来越令人沮丧之后,我放弃了。他们对所写内容的理解有多差的一个很好的迹象是对主题的非常混乱和几乎难以辨认的呈现。
作为最后的想法,如果你需要高精度浮点计算,在过去的 20 年中浮点代码取得了巨大的进步,并且对 96 位和Quadruple Precision float 的硬件支持就在身边角落,但是如果存储值的操作很重要,那么那里有很好的任意精度库。
【讨论】:
不仅特定于 MySQL,float 和 decimal 类型之间的区别在于它们表示小数值的方式。浮点类型以二进制表示分数,只能将值表示为 {m*2^n | m, n Integers} 。无法精确表示 1/5 等值(没有舍入误差)。十进制数字同样受到限制,但代表像{m*10^n | m, n Integers} 这样的数字。小数仍然不能表示像 1/3 这样的数字,但在许多常见领域(如金融)中经常出现这种情况,期望始终可以表示某些小数而不会失去保真度。由于十进制数可以表示像$0.20(五分之一美元)这样的值,因此在这些情况下是首选。
【讨论】:
decimal 用于固定数量(如货币),您需要特定的小数位数。浮点数用于存储...浮点精度数。
【讨论】:
mysql> CREATE TABLE num(id int ,fl float,dc dec(5,2));
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO num VALUES(1,13.75,13.75);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO num VALUES(2,13.15,13.15);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM num WHERE fl = 13.15;
Empty set (0.00 sec)
mysql> SELECT * FROM num WHERE dc = 13.15;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
mysql> SELECT SUM(fl) ,SUM(dc) FROM num;
+--------------------+---------+
| SUM(fl) | SUM(dc) |
+--------------------+---------+
| 26.899999618530273 | 26.90 |
+--------------------+---------+
1 row in set (0.00 sec)
mysql> SELECT * FROM num WHERE ABS(fl - 13.15)<0.01;
+------+-------+-------+
| id | fl | dc |
+------+-------+-------+
| 2 | 13.15 | 13.15 |
+------+-------+-------+
1 row in set (0.00 sec)
【讨论】:
我发现这很有用:
通常,浮点值适用于科学计算,但不应用于财务/货币价值。对于面向业务的数学,请始终使用小数。
来源:http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
【讨论】:
如果你追求的是性能而不是精度,你应该注意使用浮点数的计算比小数快得多
【讨论】:
浮点类型(近似值) - FLOAT、DOUBLE
FLOAT 和 DOUBLE 类型表示近似数值数据值。 MySQL 对单精度值使用四个字节,对双精度值使用八个字节。
对于 FLOAT,SQL 标准允许在括号中的关键字 FLOAT 后面以位为单位指定精度(但不是指数范围)的可选规范。 MySQL 也支持这种可选的精度规范,但精度值仅用于确定存储大小。从 0 到 23 的精度会产生一个 4 字节的单精度 FLOAT 列。从 24 到 53 的精度会产生一个 8 字节的双精度 DOUBLE 列。
MySQL 允许使用非标准语法:FLOAT(M,D) 或 REAL(M,D) 或 DOUBLE PRECISION(M,D)。这里,“(M,D)”是指总共最多可以存储M位的值,其中D位可以在小数点之后。例如,定义为 FLOAT(7,4) 的列在显示时看起来像 -999.9999。 MySQL 在存储值时会进行舍入,因此如果将 999.00009 插入 FLOAT(7,4) 列,则近似结果为 999.0001。
由于浮点值是近似值,而不是存储为精确值,因此在比较中尝试将它们视为精确值可能会导致问题。它们还受制于平台或实现依赖项。
为了获得最大的可移植性,需要存储近似数值数据值的代码应使用 FLOAT 或 DOUBLE PRECISION,不指定精度或位数。
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
浮点值问题
浮点数有时会引起混淆,因为它们是近似值而不是存储为精确值。 SQL 语句中写入的浮点值可能与内部表示的值不同。尝试在比较中将浮点值视为精确可能会导致问题。它们还受平台或实现依赖关系的影响。 FLOAT 和 DOUBLE 数据类型受这些问题的影响。对于 DECIMAL 列,MySQL 执行精度为 65 位小数的操作,这应该可以解决最常见的不准确问题。
以下示例使用 DOUBLE 来演示使用浮点运算完成的计算如何受到浮点错误的影响。
mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
-> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
-> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
-> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
-> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
-> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+-------+------+
| 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 |
| 6 | -51.4 | 0 |
+------+-------+------+
结果是正确的。虽然前五个记录看起来不应该满足比较(a 和 b 的值似乎没有不同),但它们可能会这样做,因为数字之间的差异显示在小数点后十位左右,具体取决于因素例如计算机体系结构或编译器版本或优化级别。例如,不同的 CPU 可能会以不同的方式评估浮点数。
如果列 d1 和 d2 被定义为 DECIMAL 而不是 DOUBLE,则 SELECT 查询的结果将只包含一行 - 上面显示的最后一行。
进行浮点数比较的正确方法是首先确定数字之间差异的可接受容差,然后与容差值进行比较。例如,如果我们同意如果浮点数在万分之一 (0.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;
在某些平台上,SELECT 语句返回 inf 和 -inf。在其他情况下,它返回 0 和 -0。
上述问题的一个含义是,如果您尝试通过在主服务器上使用 mysqldump 转储表内容并将转储文件重新加载到从服务器来创建复制从服务器,则两台主机之间包含浮点列的表可能会有所不同。
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
【讨论】:
硬性规定
如果您只需要加、减或乘以存储的数字,则最好使用 DECIMAL。
如果您需要对数据进行除法或任何其他形式的算术或代数运算,您几乎肯定会对浮点数感到满意。浮点库以及英特尔处理器上的浮点处理器本身具有大量操作来纠正、修复、检测和处理在执行典型数学函数(尤其是超越函数)时发生的异常暴风雪。
至于准确性,我曾经写过一个预算系统,计算 3,000 多个帐户中每个帐户的百分比贡献,对于 3,600 个预算单位,按月计算到该单位的合并节点,然后基于该百分比矩阵 (3,000 + x 12 x 3,600) 我将最高组织节点预算的金额乘以向下 3 级组织节点,然后从中计算所有 3,200 个细节单元的所有 (3,000 + 12) 值。数以百万计的双精度浮点计算,其中任何一次都将在自下而上的整合中将所有这些预测的汇总抛回组织中的最高级别。
所有这些计算后的总浮点误差为零。那是在 1986 年,今天的浮点库比当时好多了。英特尔以 80 位精度执行所有双精度的中间计算,这几乎消除了舍入误差。当有人告诉你“这是浮点错误”时,几乎可以肯定这不是真的。
【讨论】:
float(和double)表示二进制分数
decimal代表小数
【讨论】:
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
在将值设置为整数时在浮点中打印 10 但十进制 11
【讨论】: