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

Hac*_*ker 172 mysql

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

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

kan*_*008 184

是我怀疑时发现的.

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
Run Code Online (Sandbox Code Playgroud)

十进制确实完成了对这种情况应该做的事情,它截断了其余部分,从而失去了1/3部分.

因此,对于总和,小数点更好,但对于除法,浮点数更好,当然还有一些点.我的意思是,使用DECIMAL不会以任何方式为您提供"失败证明算术".

希望这可以帮助.

  • 实际上,DECIMAL的添加是错误的.如果你添加33.333333333三次你没有得到100.如果你将100除以3你没有得到一个有理数而没有一组重复的尾随数字,所以你不能将它乘以3得到100.一个计算器并试一试.从逻辑上讲,我们知道1/3 + 1/3 + 1/3应该等于3/3rds IE:1,但这类有理数不允许我们这样做.浮动答案是正确的,但你的会计师会讨厌它! (14认同)
  • 是不是`@ a`给了99.999999999000000000000000000000 DECIMAL?这在技术上是正确的. (4认同)
  • 一个很好的测试.多年前,C lib的数据转换功能通常会在与SQLServer中的数据进行比较时,将从ASCII转换为float的值产生大量微小差异.这已经不再适用了.测试是最好的策略,因为最好知道什么是权衡取舍. (3认同)

Mic*_*tta 76

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

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

  • @Pradeep:我觉得你没有回答我的问题.这可能是因为您自己不知道答案 - 也许您不方便向经理或客户询问更多细节.如果是这样的话,我建议咬紧牙关,与他们坐在一起几个小时,然后真正走过你的应用程序.什么*正好*,并且*非常详细*,是您的数据用于? (11认同)

use*_*100 19

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

DECIMAL的当前存储格式是一系列1,2,3或4字节整数,其位被连接以创建带有隐含小数点的二进制补码数,由您定义,并在您声明时存储在DB模式中列,并指定它的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位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工作来说效率低.在数据库中,您已经知道小数点的位置在前面,并且表中具有DECIMAL列值的每一行只需要查看该小数点的放置位置的唯一规范,存储在模式中作为DECIMAL(M,D)的参数作为M和D值的含义.

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

最后,如果您需要高精度浮点计算,过去20年浮点代码已经取得了巨大进步,96位和四倍精度浮点数的硬件支持即将到来,但是如果存储值的操作很重要,那么有很好的任意精度库.


Sin*_*ion 12

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


Sky*_*and 9

十进制是指固定数量,如金钱,你想要一个特定的小数位数.浮点数用于存储...浮点精度数.


小智 6

我发现这很有用:

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

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


zlo*_*ctb 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)
Run Code Online (Sandbox Code Playgroud)