• 浮点数类型讲解


    浮点类型

    1) 类型介绍

    浮点数和定点数类型的特点是可以 处理小数 ,你可以把整数看成小数的一个特例。因此,浮点数和定点 数的使用场景,比整数大多了。 MySQL支持的浮点数类型,分别是 FLOAT、DOUBLE、REAL。

    • FLOAT 表示单精度浮点数

    • DOUBLE 表示双精度浮点数

    • REAL默认就是 DOUBLE。如果你把 SQL 模式设定为启用“ REAL_AS_FLOAT ”,那 么,MySQL 就认为 REAL 是 FLOAT。如果要启用“REAL_AS_FLOAT”,可以通过以下 SQL 语句实现:

      SET sql_mode = “REAL_AS_FLOAT”;

    问题:为什么浮点数类型的无符号数取值范围,只相当于有符号数取值范围的一半,也就是只相当于 有符号数取值范围大于等于零的部分呢?

    MySQL 存储浮点数的格式为: 符号(S) 、 尾数(M) 和 阶码(E) 。因此,无论有没有符号,MySQL 的浮 点数都会存储表示符号的部分。因此, 所谓的无符号数取值范围,其实就是有符号数取值范围大于等于 零的部分。

    2) 数据精度说明

    对于浮点类型,在MySQL中单精度值使用 4 个字节,双精度值使用 8 个字节。

    • MySQL允许使用 非标准语法 (其他数据库未必支持,因此如果涉及到数据迁移,则最好不要这么 用): FLOAT(M,D) 或 DOUBLE(M,D) 。这里,M称为 精度 ,D称为 标度 。(M,D)中 M=整数位+小数 位,D=小数位。 D<=M<=255,0<=D<=30。

      例如,定义为FLOAT(5,2)的一个列可以显示为-999.99-999.99。如果超过这个范围会报错。

    • FLOAT和DOUBLE类型在不指定(M,D)时,默认会按照实际的精度(由实际的硬件和操作系统决定) 来显示。

    • 说明:浮点类型,也可以加 UNSIGNED ,但是不会改变数据范围,例如:FLOAT(3,2) UNSIGNED仍然 只能表示0-9.99的范围。

    • 不管是否显式设置了精度(M,D),这里MySQL的处理方案如下:

      • 如果存储时,整数部分超出了范围,MySQL就会报错,不允许存这样的值
      • 如果存储时,小数点部分若超出范围,就分以下情况:
        • 若四舍五入后,整数部分没有超出范围,则只警告,但能成功操作并四舍五入删除多余 的小数位后保存。例如在FLOAT(5,2)列内插入999.009,近似结果是999.01。
        • 若四舍五入后,整数部分超出范围,则MySQL报错,并拒绝处理。如FLOAT(5,2)列内插入 999.995和-999.995都会报错。
    • 从MySQL 8.0.17开始,FLOAT(M,D) 和DOUBLE(M,D)用法在官方文档中已经明确不推荐使用,将来可 能被移除。另外,关于浮点型FLOAT和DOUBLE的UNSIGNED也不推荐使用了,将来也可能被移除。

    3) 精度误差说明

    浮点数类型有个缺陷,就是不精准。下面我来重点解释一下为什么 MySQL 的浮点数不够精准。比如,我 们设计一个表,有f1这个字段,插入值分别为0.47,0.44,0.19,我们期待的运行结果是:0.47 + 0.44 + 0.19 = 1.1。而使用sum之后查询:

    CREATE TABLE test_double2(
    f1 DOUBLE
    );
    INSERT INTO test_double2
    VALUES(0.47),(0.44),(0.19);
    mysql> SELECT SUM(f1)
    -> FROM test_double2;
    +--------------------+
    | SUM(f1) |
    +--------------------+
    | 1.0999999999999999 |
    +--------------------+
    1 row in set (0.00 sec)

    查询结果是 1.0999999999999999。看到了吗?虽然误差很小,但确实有误差。 你也可以尝试把数据类型 改成 FLOAT,然后运行求和查询,得到的是, 1.0999999940395355。显然,误差更大了。

    那么,为什么会存在这样的误差呢?问题还是出在 MySQL 对浮点类型数据的存储方式上。

    MySQL 用 4 个字节存储 FLOAT 类型数据,用 8 个字节来存储 DOUBLE 类型数据。无论哪个,都是采用二 进制的方式来进行存储的。比如 9.625,用二进制来表达,就是 1001.101,或者表达成 1.001101×2^3。如 果尾数不是 0 或 5(比如 9.624),你就无法用一个二进制数来精确表达。进而,就只好在取值允许的范 围内进行四舍五入。

    在编程中,如果用到浮点数,要特别注意误差问题,因为浮点数是不准确的,所以我们要避免使用“=”来 判断两个数是否相等。同时,在一些对精确度要求较高的项目中,千万不要使用浮点数,不然会导致结 果错误,甚至是造成不可挽回的损失。那么,MySQL 有没有精准的数据类型呢?当然有,这就是定点数 类型: DECIMAL 。

  • 相关阅读:
    权限系统中的数据权限就该这么设计,yyds
    ANACONDA的进阶理解和思考
    lambda 自定义收集器
    3、AWS SDK for Go使用
    [基础服务] Jenkins的安装和部署
    [UE]常见数学和插值
    邻接矩阵的COO格式
    两个三位电云获取旋转矩阵
    逃避型人格分析,如何改变逃避型性格?
    c++11 多线程支持 条件变量(condition_variable)(三)
  • 原文地址:https://blog.csdn.net/Leon_Jinhai_Sun/article/details/127817732