PHP将精度保存到MYSQL中的结果以四舍五入的结果字段结尾

时间:2018-07-31 17:25:18

标签: php mysql precision

我已经阅读了有关浮点数的所有算术知识,但我只是想准确地存储那些令人毛骨悚然的东西。

我有一个类型为DECIMAL (40,20)的mysql字段。

我正在46457.67469999996的php中保存一个值。使用此值更新记录后,最终结果为46457.67470000000000000000。不确定为什么只将其四舍五入只是保存到数据库中。

该值未预先转换为字符串或任何其他内容。传递给PDO的字段值是我希望保存的值,并以浮点数的形式返回。也许是因为我将PHP浮点数保存为发生舍入的mysql十进制类型?

我在这里想念什么?

编辑:添加了出现问题的示例代码

// Query placeholder variables.  Hard-coded for the example test
$query_vars = array(
    ":vendor_id"                    => 33154,
    ":year"                         => 2018,
    ":coop_committed_dollar"        => 46457.67469999996,
    ":coop_committed_dollar_update" => 46457.67469999996
);

$statement = "  INSERT INTO vendor_data_yearly
                (vendor_id, year, coop_committed_dollar) VALUES
                (:vendor_id, :year, :coop_committed_dollar)
                ON DUPLICATE KEY UPDATE
                    coop_committed_dollar = :coop_committed_dollar_update;";
$query = $connection->conn->prepare($statement);
$query->execute($query_vars);

运行此命令时,coop_committed_dollar的结果值为46457.67470000000000000000。这段代码是我所做的一切合法的。

可能的解决方案

// Note that I am casting the string using the BC Math library.
// I dunno how to just initialize the number (lame documentation), so I'm adding 0 to it.
$number = "46457.674699999967";
$number = bcadd("46457.674699999967", 0, 20);

$query_vars = array(
    ":vendor_id"                    => 33154,
    ":year"                         => 2018,
    ":coop_committed_dollar"        => $number,
    ":coop_committed_dollar_update" => $number
);

$statement = "  INSERT INTO vendor_data_yearly
                (vendor_id, year, coop_committed_dollar) VALUES
                (:vendor_id, :year, :coop_committed_dollar)
                ON DUPLICATE KEY UPDATE
                    coop_committed_dollar = :coop_committed_dollar_update;";
$query = $conn->prepare($statement);
$query->execute($query_vars);

这将导致数据库中出现预期的数字。

我发现只能正确解决的解决方案

我正在使用的数据通过ajax传递。我必须采取一些步骤才能使其正常工作。

  1. 使用ini_set('precision', 20);
  2. 在通过ajax发送数据之前,将有问题的数据手动设置为字符串,这样PHP不会将其舍入,扩展额外的浮点数,填充等。

我发现PHP不会只允许我可靠地使用来自脚本范围(ajax)之外的变量集的大量数字。一旦PHP掌握了这个数字,它将做它必须做的事才能使它成为一个浮点数。

如果有人能在这种情况下找到更好的解决方案,那我真是耳目一新了:)

1 个答案:

答案 0 :(得分:2)

问题在于PHP的精度不允许您存储您认为要存储的确切数字。 当您设置":coop_committed_dollar" => 46457.67469999996时 实际上,PHP会将其存储为其他值,具体取决于精度。

解决方案是将值作为字符串而不是浮点数存储在PHP中。

由于您的问题是:“我想念的是什么”,我将尝试提供答案。 基本上,归结为使用二进制表示在内部存储浮点数。由于46457.67469999996不能完全是二进制的(最终以无穷大数表示,类似于以10为底的33%(.3333 ...)),因此根据PHP的精度(在php ini中设置)使用最接近的舍入。 / p>

this question中给了我很好的解释,我刚才问过。

在您的特定情况下,当通过PHP在服务器端进行解析时,似乎还通过AJAX发送的值被存储为浮点数。您希望将其存储为字符串。如果您使用的是json_decode,请添加以下选项:JSON_BIGINT_AS_STRING