好的。我可能在這裏很沉悶(據瞭解),但是我在PHP 5.3.x的MySQLi中發現了一個沒有記錄的準備語句的「特性」,或者我錯過了一些非常基本的東西。PHP/MySQLi使用預處理語句返回不正確的浮點值
短版 - 通過的MySQLi和mysqlnd驅動器返回不正確浮在PHP編寫的語句值
龍版
首先,一些測試數據
mysql> CREATE TABLE `t2` (`v` float(6,2) NOT NULL DEFAULT '0.00');
Query OK, 0 rows affected (0.08 sec)
mysql> insert into t2 (v) values (0.03);
Query OK, 1 row affected (0.00 sec)
問題通過準備好的聲明檢索上述值時出現。當使用傳統mysql _...或標準mysqli ...查詢調用時,返回正確的數據。然而,通過一份聲明中使用相同的查詢返回不正確的值:
測試代碼:
atom:~/testScripts> cat f1.php
<?php
require('passwds.php');
$q="select * from t2"; // same query for all
echo "/* Old style MySQL statements (deprecated) */".PHP_EOL;
$h1=mysql_connect(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD);
mysql_select_db('test',$h1);
$r1=mysql_query($q);
while ($f1=mysql_fetch_assoc($r1))
{
echo print_r($f1,true).PHP_EOL;
}
echo "/* New style MySQLi statements */".PHP_EOL;
$h2=new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD,'test');
$r2=$h2->query($q);
while ($f2=$r2->fetch_assoc())
{
echo print_r($f2,true).PHP_EOL;
}
echo "/* New style MySQLi prepared statements */".PHP_EOL;
$h3=new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASSWORD,'test');
$s3=$h3->stmt_init();
$s3->prepare($q);
$s3->execute(); // no binding required
$r3=$s3->get_result();
while ($f3=$r3->fetch_assoc())
{
echo print_r($f3,true).PHP_EOL;
}
結果:
atom:~/testScripts> php -f f1.php
/* Old style MySQL statements (deprecated) */
Array
(
[v] => 0.03
)
/* New style MySQLi statements */
Array
(
[v] => 0.03
)
/* New style MySQLi prepared statements */
Array
(
[v] => 0.029999999329448
)
如果我在表t2
改變v
類型的DOUBLE
而不是FLOAT
預準備語句返回的值是正確的。
在Linux機器上運行腳本(OpenSuse 12.1 32位,MySQL和PHP編譯源代碼)和Windows 7(64位PHP安裝了二進制代碼,數據來自Linux機器)。我也嘗試過使用OpenSuse 12.1 64位安裝(同樣使用mysqlnd驅動程序從源代碼安裝PHP和MySQL),結果相同。所有型號都使用與PHP提供的mysqlnd
司機
問題我錯過了一些非常基本的或者我應該報告給PHP.NET一個錯誤?
對不起這是一個漫長的問題,但我想我會提供儘可能多的數據,我可以
我的0.02美元是你錯過了一些非常基本的東西 - 漂浮的方式工作。浮游物不用於存儲任何精確的東西。這就是通常的計算方式,而不僅僅是這裏。 – eis 2012-07-18 19:07:01
我知道浮點數永遠不會用二進制精確地存儲(我已經老了,並且這樣做的時間太長了),但我很困惑,爲什麼我使用兩個不同的查詢系統使用相同的PHP SQL驅動程序得到不同的結果。下面的J米勒已經擊中了頭部。儘管感謝您的評論。非常感謝 – DaveyBoy 2012-07-18 19:33:58