php - PHP 将精度浮点数保存到 MYSQL 最终得到舍入的结果字段
问题描述
我已经阅读了有关浮点数的所有算术知识,但我只是想准确地存储该死的东西。
我有一个类型为DECIMAL (40,20)
.
我在 php 中保存一个值46457.67469999996
。使用此值更新记录后,最终结果为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 传入的。我必须采取一些步骤才能使其正常工作。
- 利用
ini_set('precision', 20);
- 在通过 ajax 发送之前手动将有问题的数据设置为字符串,这样 PHP 就不会对其进行舍入,扩展额外的浮点疯狂,填充它等。
我发现 PHP 不会让我可靠地处理来自脚本范围 (ajax) 之外的变量集的大量数字。一旦 PHP 掌握了这个数字,它就会做它必须做的事情,以使它作为一个浮点数有意义。
如果有人对这种特殊情况有更好的解决方案,我会全神贯注:)
解决方案
问题是 PHP 的精度不允许您存储您认为正在存储的确切数字。当您设置":coop_committed_dollar" => 46457.67469999996
PHP 时,实际上将其存储为不同的值,具体取决于精度。
解决方案是将 PHP 中的值存储为字符串而不是浮点数。
由于您的问题是:“我错过了什么”,我将尝试提供答案。基本上它归结为使用二进制表示在内部存储浮点数。由于 46457.67469999996 不能完全是二进制(它最终是一个无限数,类似于 base-10 中的 33% (.3333...)),因此基于 PHP 的精度(在 php ini 中设置)使用最接近的舍入。
我在不久前问过的这个问题中得到了很好的解释。
在您的特定情况下,您通过 AJAX 发送的值在服务器端由 PHP 解析时似乎也被存储为浮点数。您希望将其存储为字符串。如果您使用的是 json_decode,请添加此选项:JSON_BIGINT_AS_STRING。
推荐阅读
- google-data-studio - Google Data Studio 连接器中缺少 Google Search Console 数据(不在 GSC 本身中)
- javascript - 格式化动态列 JavaScript
- audio - 播放前 HTML5 音频长缓冲
- python - ImportError:numpy.core.multiarray 导入失败(cv2)
- prolog - SICStus Prolog sat_count/2 替换?
- r - 根据列的内容在 R 中重复行
- azure-logic-apps - 在 Azure 逻辑应用中检索 json 属性值
- python-3.x - @property - 方法调用逻辑
- php - 使用 Mailer 在生产中接收消息时出现问题
- android - 为什么片段中的生命周期范围.launch 会阻塞 UI 线程?