我已经读过所有关于浮点数的算术,但我只是想准确地存储这些该死的东西。
我有一个类型为DECIMAL (40,20)
的mysql字段。
我正在46457.67469999996
的php中保存一个值。在用这个值更新记录之后,最终结果是46457.67470000000000000000
。不知道为什么它会被四舍五入,只是被保存到数据库中。
该值没有预先转换为字符串或任何内容。传递到PDO中的字段值是我期望保存的值,它以浮点形式返回。。。也许是因为我将一个PHP浮点保存为一个mysql十进制类型,在这里进行舍入?
我在这里错过了什么?
EDIT:添加了存在问题的示例代码
// 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就不会对其进行舍入、用额外的浮点疯狂扩展、padd等
我发现PHP不允许我可靠地处理来自脚本范围之外的变量集(ajax(的大量数据。一旦PHP掌握了这个数字,它就会做它必须做的事情,以使它作为一个浮点值有意义。
如果有人对这个特定的场景有更好的解决方案,我会全力以赴:(
问题是PHP的精度不允许您存储您认为要存储的确切数字。设置":coop_committed_dollar" => 46457.67469999996
时PHP实际上是将其存储为不同的值,具体取决于精度。
解决方案是将值存储在PHP中作为字符串而不是浮点值。
既然你的问题是:"我错过了什么",我会尽力提供一个答案。基本上,它可以归结为使用二进制表示在内部存储浮点值。由于46457.767469999996不能完全是二进制的(它最终是一个无穷大的数字,类似于10进制中的33%(.3333…((,因此根据PHP的精度(在PHP.ini中设置(使用最接近的四舍五入。
我刚才问的这个问题给了我一个很好的解释。
在您的特定情况下,当PHP在服务器端解析时,您通过AJAX发送的值似乎也被存储为浮点值。您希望将其存储为字符串。如果您正在使用json_decode,请添加此选项:json_BIGINT_AS_STRING。