【问题标题】:PHP PDO query returns inaccurate value for FLOAT fieldsPHP PDO 查询为 FLOAT 字段返回不准确的值
【发布时间】:2013-06-11 23:59:12
【问题描述】:

我猜这之前已经出现过,但我找不到我的问题的答案。这是一个小代码sn-p:

    $stmt = $this -> db -> query("
        SELECT
          `Field`
        FROM
          `Table`
        WHERE
          (`ID` = 33608)");
    var_dump($stmt -> fetch());

这是我得到的结果:

    array(1) { ["Field"]=> float(1.7999999523163) }

但是,MySQL 数据库中的数据是 1.8。该字段的类型是 float(7,4)。 $this->db 是一个 PDO 对象。 我最近迁移到 PDO(来自 AdoDB),并且这段代码之前运行良好。我不确定这里出了什么问题。你能指出我正确的方向吗? 谢谢!

【问题讨论】:

  • 我无法重现它。您是否在 PDO 构造函数中传递了任何特定设置?
  • PDO 的 MySQL 驱动程序根据 PDO::ATTR_EMULATE_PREPARES 设置返回浮点数或字符串,但我仍然得到 float(18)string(7) "18.0000" :-?
  • 这是我用来初始化 PDO 的(抱歉,我不知道如何在此处添加代码块):尝试 { $pdo = new Db("mysql:host=".DBHOST. ";dbname=".DBNAME.";charset=utf8", DBUSER, DBPASS); $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo -> setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch (PDOException $e) { die('DB Error'); }

标签: php mysql pdo


【解决方案1】:

Floating-Point Types (Approximate Value) - FLOAT, DOUBLE 中所述:

MySQL 在存储值时会进行舍入,因此如果将999.00009 插入FLOAT(7,4) 列,则近似结果为999.0001

由于浮点值是近似值,而不是存储为精确值,因此在比较中尝试将它们视为精确值可能会导致问题。它们还受平台或实现依赖关系的影响。欲了解更多信息,请参阅Section C.5.5.8, “Problems with Floating-Point Values”

为了获得最大的可移植性,需要存储近似数值数据值的代码应使用FLOATDOUBLE PRECISION,不指定精度或位数。

因此,在将1.8 插入数据库后,MySQL 将文字四舍五入为001.8000,并以binary32 格式将最接近的近似编码为该数字:即0x3FE66666,其位表示:

签名 : 0b0 有偏指数:0b01111111 = 127(表示包括 +127 的偏差,因此 exp = 0) 有效位 : 0b[1.]11001100110011001100110 ^ 隐藏位,不以二进制表示形式存储 = [1.]7999999523162841796875

这相当于:

(-1)^0 * 1.7999999523162841796875 * 2^0 = 1.7999999523162841796875

这是 MySQL 返回给客户端的值。看起来 AdoDB 然后检查了列的数据类型并对结果进行了相应的四舍五入,而 PDO 没有。

如果您想要精确的值,您应该使用fixed point datatype,例如DECIMAL

【讨论】:

    【解决方案2】:

    如果您想要准确的值,您必须使用 DECIMAL 字段类型而不是 FLOAT
    而PDO与它无关。它与计算机的一般工作方式相当相关。

    【讨论】:

    • 使用 DECIMAL 会产生不良的副作用,即 PDO 将返回值作为 STRING 无论您是否将 ATTR_EMULATE_PREPARES 设置为 FALSE 并且您使用的是正确的 mysqlnd司机。所以,根据他的需要,他最好坚持FLOAT
    猜你喜欢
    • 2017-11-02
    • 2015-04-09
    • 2010-11-06
    • 2012-05-16
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 2021-02-15
    相关资源
    最近更新 更多