浮点数与小数点数据types的区别
当我在MySQL中使用float和decimal数据types时,它有什么不同?
我应该什么时候使用哪个?
这是我怀疑时发现的。
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不会给你一个“失败certificate算术”。
希望这可以帮助。
大多数环境中的“浮点”是二进制浮点types。 它可以准确地存储base-2值(到某个点),但不能准确地存储许多base-10(十进制)值。 浮游物最适合科学计算。 他们不适合大多数商业导向的math,不适当的使用浮游物会咬你。 许多十进制值不能在base-2中精确表示。 0.1
不能,例如,所以你看到奇怪的结果,如1.0 - 0.1 = 0.8999999
。
十进制存储基数为10的数字。 十进制是大多数商业math的一种很好的types(但任何内置的“金钱”types更适合于财务计算),其中值的范围超过整数types提供的值,并且需要小数值。 小数,正如其名称所暗示的,是为10位数字devise的 – 它们可以精确地存储十进制值(再次,到某一点)。
MySQL最近改变了他们存储DECIMALtypes的方式 。 在过去,它们为每个数字存储字符(或低位字节),该字符包括一个数字的ASCII(或nybble)表示,或一个二进制补码整数或其某种导数。
DECIMAL的当前存储格式是一系列的1,2,3或4个字节的整数,它们的位被连接起来以创build一个二进制补码,并带有一个由您定义的隐含小数点,并在声明时存储在数据库模式中该列并指定它的DECIMAL大小和小数点位置。
举个例子,如果你使用一个32位的int,你可以存储从0到4,294,967,295的任何数字。 那将只能可靠地覆盖999,999,999,所以如果你抛出2位并使用(1 << 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位低位:72位
作为2个32位整数:64位
目前DECIMAL最多支持65位数,如DECIMAL(M,D),其中允许M的最大值为65,允许的最大D值为30。
因此,一次不要求9个数字块,小于32位的整数用于使用1,2和3个字节的整数来添加数字。 由于某些原因,违反逻辑,签名,而不是使用无符号整数,这样做,1位被抛出,导致以下存储function。 对于1,2和4字节的整数,丢失的位并不重要,但是对于3字节的整数来说,这是一个灾难,因为丢失了一位整数。
用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上完成的浮点计算还要慢。
在存储效率方面,因为浮点数的指数被附加到每个浮点数上,隐式地指定小数点的位置,因此是大量冗余的,因此DB工作效率低下。 在数据库中,您已经知道小数点在哪里,而表中每行都有一个DECIMAL列的值,只需要查看小数点的位置和存储位置在模式中作为DECIMAL(M,D)的参数,作为M和D值的含义。
在这里发现的关于哪种格式将被用于各种应用程序的许多评论是正确的,所以我不会重视这一点。 我花时间在这里写这篇文章,因为谁在维护链接的MySQL在线文档都不理解上述任何内容,而且越来越多的挫败尝试向他们解释,我放弃了。 一个很好的证据表明,他们对自己写的东西的理解程度如何差,这个主题是非常混乱且几乎无法解读的。
作为最后的想法,如果您需要高精度浮点运算,过去20年来浮点代码有了巨大的进步,96位和Quadruple Precision浮点的硬件支持就在眼前,但是如果存储值的操作很重要,那么就有很好的任意精度库。
不仅仅是针对MySQL,浮点数和小数types之间的区别在于它们表示小数值的方式。 浮点types表示二进制的分数,只能表示为{m*2^n | m, n Integers}
{m*2^n | m, n Integers}
。 例如1/5的值不能被精确地表示(没有舍入误差)。 十进制数字同样受到限制,但表示数字如{m*10^n | m, n Integers}
{m*10^n | m, n Integers}
。 小数仍然不能代表像1/3那样的数字,但是在许多常见的领域(例如金融)中通常是这样的,期望的是,可以始终expression某些小数而不丢失保真度。 由于十进制数可以表示像$0.20
(五分之一美元)的值,所以在这些情况下是优选的。
十进制是固定数量,如金钱,你想要一个特定的小数位数。 浮点数用于存储浮点精度数字。
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)
浮动:
一个小的(单精度)浮点数。 允许值是-3.402823466E + 38到-1.175494351E-38,0和1.175494351E-38到3.402823466E + 38。 这些是基于IEEE标准的理论极限。 实际的范围可能会稍微小一点取决于您的硬件或操作系统。
十进制:
精确的“定点”号码。 M是总位数(精度),D是小数点后的位数(标度)。 小数点和(对于负数)“ – ”符号不计入inM。 如果D是0,则数值没有小数点或小数部分。 DECIMAL的最大位数(M)为65.支持的最大小数位数(D)为30.如果省略D,则缺省值为0.如果省略M,则缺省值为10。
我发现这很有用:
一般而言,浮动价值对于科学计算是有利的,但不应该用于金融/货币价值。 对于面向业务的math,总是使用十进制。
资料来源: http : //code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
如果你是在性能之后,而不是精确度,你应该注意,使用浮点数的计算速度比小数快得多
浮点types(近似值) – FLOAT,DOUBLE
FLOAT和DOUBLEtypes表示近似的数字数据值。 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。
由于浮点值是近似值,并不是以精确值的forms存储的,因此尝试将它们作为比较对待可能会导致问题。 他们也受到平台或实施依赖关系的影响。
为了最大限度的便携性,需要存储近似数字数据值的代码应该使用FLOAT或DOUBLE PRECISION,而不需要指定精度或位数。
https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
浮点值的问题
浮点数有时会造成混淆,因为它们是近似值,并不作为精确值存储 。 写入SQL语句中的浮点值可能与内部表示的值不同。 尝试将浮点值视为比较精确可能会导致问题。 他们也受到平台或实施依赖关系的影响。 FLOAT和DOUBLE数据types受到这些问题的影响。 对于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 | +------+-------+------+
结果是正确的。 尽pipe前五个logging看起来不应该满足比较(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)
相反,要获得数字相同的行,testing应该在容差值内find差异:
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转储表内容并将转储文件重新加载到从服务器来创build复制从服务器,则包含浮点列的表可能在两个主机之间有所不同。
https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
严格和快速的规则
如果您只需要添加,减去或乘以您存储的数字,DECIMAL就是最好的。
如果你需要在数据上划分或者做任何其他forms的算术或代数,那么你几乎肯定会浮起来更快乐。 浮点库和英特尔处理器上的浮点处理器本身都具有TON操作来修正,修复,检测和处理在执行典型的math函数(特别是超越函数)时发生的exception的暴风雪。
至于准确性,我曾经写过一个预算系统,按每个月3000个预算单位,向该单位的合并节点计算每个3,000+个账户的贡献百分比,然后根据该百分比matrix(3,000 + x 12 x 3,600)我把最高组织节点的预算金额乘以组织节点的下三个级别,然后计算所有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