float和decimal数据类型之间的差异

时间:2011-03-01 03:49:12

标签: mysql

当我在MySQL中使用float和decimal数据类型时,它有什么不同?

我什么时候应该使用哪个?

12 个答案:

答案 0 :(得分:177)

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不会给 无论如何,你都是“失败证明算术”。

希望这会有所帮助。

答案 1 :(得分:74)

大多数环境中的“float”是二进制浮点类型。它可以准确地存储base-2值(到某个点),但不能准确存储许多base-10(十进制)值。浮子最适合科学计算。他们适合大多数面向商业的数学,不恰当的使用花车会咬你。许多十进制值无法在base-2中精确表示。例如,0.1不能,因此您会看到像1.0 - 0.1 = 0.8999999这样的奇怪结果。

十进制存储基数为10的数字。对于大多数商业数学而言,十进制是一个很好的类型(但任何内置的“货币”类型更适合于财务计算),其中值的范围超过整数类型提供的值,并且需要小数值。顾名思义,小数是为基数10设计的 - 它们可以精确地存储小数值(再次,到某一点)。

答案 2 :(得分:19)

MySQL最近改变了他们存储DECIMAL type的方式。在过去,他们为每个数字存储字符(或nybbles),包括数字的ASCII(或nybble)表示 - vs - 二进制补码整数或其衍生物。

DECIMAL的当前存储格式是一系列1,2,3或4字节整数,其位被连接以创建带有隐含小数点的二进制补码数,由您定义并存储在DB模式中当您声明列并指定它的DECIMAL大小和小数点位置时。

举例来说,如果采用32位int,则可以存储0 - 4,294,967,295之间的任何数字。那将只能可靠地覆盖999,999,999,所以如果你扔出2位并使用(1 <&lt;&lt; 30 -1)你就什么也不放弃。仅使用4个字节覆盖所有9位数字比使用4个ASCII字符或8个nybble数字覆盖32位中的4位数字更有效。 (一个nybble是4位,允许值0-15,超过0-9所需的值,但你不能通过转到3位来消除这种浪费,因为它只涵盖0-7的值)

MySQL在线文档中使用的示例使用DECIMAL(18,9)作为示例。这比隐含小数点前面的9位数字和9位数字要短,如上所述,需要进行以下存储。

作为18个8位字符: 144位

作为18个4位nybbles: 72位

作为2个32位整数: 64位

目前DECIMAL最多支持65位数字,如DECIMAL(M,D),其中M允许的最大值为65,允许的最大D值为30。

为了不一次要求9位数的块,小于32位的整数用于使用1,2和3字节整数来添加数字。出于某种原因,无视逻辑,使用了签名而不是无符号的int,并且这样做,1位被抛出,从而产生以下存储能力。对于1,2和4字节的整数,丢失的位无关紧要,但对于3字节的int来说,这是一场灾难,因为整个数字由于丢失了这一位而丢失。

使用7位int: 0 - 99

使用15位int: 0 - 9,999

使用23位int:  0 - 999,999 (0 - 9,999,999,24位int)

1,2,3和4字节整数连接在一起形成“位池”DECIMAL用于将数字精确地表示为二进制补码整数。小数点未存储,暗示。

这意味着数据库引擎不需要ASCII到int转换就可以将“数字”转换为CPU识别为数字的内容。没有舍入,没有转换错误,它是CPU可以操作的实数。

对这个任意大整数的计算必须在软件中完成,因为这种数字没有硬件支持,但这些库非常陈旧且经过高度优化,50年前编写,以支持IBM 370 Fortran任意精度浮点数据。它们仍然比使用CPU整数硬件完成的固定大小整数代数慢,或者在FPU上进行浮点计算。

就存储效率而言,因为float的指数附加到每个浮点数,隐含地指定小数点的位置,所以它是大量冗余的,因此对DB工作来说效率低。在DB中,您已经知道小数点的位置在前面,并且表中具有DECIMAL列值的每一行只需要查看1&amp;仅指定小数点的放置位置,存储在模式中作为DECIMAL(M,D)的参数,作为M和D值的含义。

这里发现的关于哪种格式用于各种应用程序的许多评论是正确的,所以我不会强调这一点。我花时间在这里写这篇文章,因为无论是谁维护链接的MySQL在线文档都不理解上述任何内容,并且经过多次令人沮丧的尝试向他们解释它后,我放弃了。很好地表明他们对所写内容的理解程度有多差,这是对主题的非常混乱和难以理解的表现。

最后一点,如果您需要高精度浮点计算,过去20年浮点代码已经取得了巨大进步,96位和Quadruple Precision float的硬件支持是就在拐角处,但如果存储值的操作很重要,那么有很好的任意精度库。

答案 3 :(得分:12)

不仅仅特定于MySQL,float和decimal类型之间的区别在于它们表示小数值的方式。浮点类型表示二进制的分数,它只能将值表示为{m*2^n | m, n Integers}。诸如1/5之类的值无法精确表示(没有舍入误差)。十进制数字同样受限,但代表{m*10^n | m, n Integers}之类的数字。小数仍然不能代表1/3这样的数字,但在许多常见领域(例如金融)中经常会出现这样的情况,即期望是某些小数部分总是可以表达而不会失去保真度。由于十进制数字可以表示像$0.20(五分之一美元)的值,因此在这些情况下是首选。

答案 4 :(得分:9)

十进制是指固定数量,如金钱,您需要特定的小数位数。浮点数用于存储...浮点精度数。

答案 5 :(得分:5)

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)

答案 6 :(得分:4)

我觉得这很有用:

  

通常,Float值适用于科学计算,但不应用于财务/货币价值。对于面向业务的数学,请始终使用十进制。

来源:http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/

答案 7 :(得分:2)

如果你追求的是性能而不是精确度,你应该注意浮点计算比小数快得多

答案 8 :(得分:2)

浮点类型(近似值) - 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

答案 9 :(得分:0)

Hard & Fast Rule

If all you need to do is add, subtract or multiply the numbers you are storing, DECIMAL is best.

If you need to divide or do any other form of arithmetic or algebra on the data you're almost certainly going to be happier with float. Floating point libraries, and on Intel processors, the floating point processor itself, have TONs of operations to correct, fix-up, detect and handle the blizzard of exceptions that occur when doing typical math functions - especially transcendental functions.

As for accuracy, I once wrote a budget system that computed the % contribution of each of 3,000+ accounts, for 3,600 budget units, by month to that unit's consolidation node, then based on that matrix of percentages (3,000 + x 12 x 3,600) I multiplied the amounts budgeted by the highest organizational nodes down to the next 3 levels of the organizational nodes, and then computed all (3,000 + 12) values for all 3,200 detail units from that. Millions and millions and millions of double precision floating point calculations, any one of which would throw off the roll-up of all of those projections in a bottoms-up consolidation back to the highest level in the organization.

The total floating point error after all of those calculations was ZERO. That was in 1986, and floating point libraries today are much, much better than they were back then. Intel does all of it's intermediate calculations of doubles in 80 bit precision, which all but eliminates rounding error. When someone tells you "it's floating point error" it's almost certainty NOT true.

答案 10 :(得分:-1)

float(和double)代表二进制分数

decimal表示小数部分

答案 11 :(得分:-2)

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时,

在float中 但在十进制11