An example may show the problem. Watch the floats!
db_query("INSERT chatblock (message, username, timestamp) VALUES (%s, %s, %f)", 'test','user', 1179230890.96152);
The resulting database row will contain this microtime timestamp for only 2 decimals precision.
I have found out that preg_replace_* functions of PHP 4 are truncating floating numbers (like echo does).
Try it yourself.
$a=1179229804.75932400;
var_dump( preg_replace("/sg_to_be_replaced/", (float)$a, "sg_to_be_replaced") );
Yields:
string(13) "1179229804.76"
$a=1179229804.75932400;
var_dump( preg_replace("/sg_to_be_replaced/", sprintf("%f", $a), "sg_to_be_replaced") );
Results:
string(17) "1179229804.759324"
I have modified my include/database.inc so _db_query_callback replaces floats with a sprintf string
case '%f':
return sprintf("%f", array_shift($args));
# return (float) array_shift($args);
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | database_11.patch | 554 bytes | kaerast |
| #1 | database_10.patch | 553 bytes | kaerast |
Comments
Comment #1
kaerast commentedThis is a problem in Head as well and will probably want fixing there first. Attached is a patch against Drupal 6, but it should apply for Drupal 5 as well.
Is there any reason not to use sprintf here?
Comment #2
ChrisKennedy commentedYou need a space after the comma, and you might as well use single quotes.
Comment #3
kaerast commentedRe-written the patch according to ChrisKennedy's comment.
Comment #4
dries commentedI tried searching the PHP documentation to confirm this -- could you find an official statement about this behavior. It sounds very weird.
An alternative to printf, might be to use a number formatter.
Either way, this needs to be documented in the code. People are bound to frown at that construct and might wonder why we don't cast that string to a float.
But honestly, I'm not convinced that this is a bug. It means that the calling function is passing in a string, while it really should pass in a valid float. The loss of precision might not happen when you pass in a real float, rather than a string.
I'd like to see us investigate this some more ...
Comment #5
ainigma32 commentedI tried to reproduce the examples on Apache 1.3 with PHP 4.3.5 (minimum required for Drupal) and it looks like this has something to do with the precision ini-setting. The following code illustrates this:
It looks like the preg_replace function converts the float to a string using the precision ini-setting while sprintf seems to ignore the setting and only drops the (unnecessary) last two zeros.
So I suppose the question is now: should we change the precision ini-setting, do we start using sprintf or is there another solution out there?
You PHP gurus out there, feel free to jump in anytime ;-)
Also tried this little script on Apache 2.2 and PHP 5.2.6 and it produces the same result.
Comment #6
dpearcefl commentedClosing this issue because of a lack of activity.
Comment #7
Gabriel R. commented@ubul : you will have to make sure the value is float, just convert it, like:
(float) 12.34or(float) $myvalue