I found this problem, when I was trying to benchmark my code. It seems that BC Math extension, which is built-in to PHP since version 4.? does not work properly with PHP GTK.
I tried this example both with PHP-GTK and regular PHP and I get different results. I am not sure if this is a missing feature or a bug. My installation is PHP-GTK 2.0.1 from gtk.php.net (binary and extensions).
bcsub (or any other BC Math) function exists, it just doesn't work. I even tried supplying floats directly as arguments - always returns 0.000000.
<?php
if (!function_exists('bcsub'))
die('BC Math not present!');
$a = microtime(true); //start time -
// with true argument returns a float unix timestamp with microseconds as a decimal
usleep(0.5 * 1000000); //sleep for half a second
$b = microtime(true); //end time
echo "$a versus $b\n"; // just checking if the values are correct
$substract = $b - $a; // substracting them "manually"
$bcsubstract = bcsub($b, $a, 6); // this should be better than substraction, as it provides more useful results
echo "substracted: $substract\n".
"bcsubbed: $bcsubstract"; //just dumping the result
?>
yield with PHP 5.2.9 - as expected:
1243685894.4375 versus 1243685894.9369
substracted: 0.49937701225281
bcsubbed: 0.499400
yield with PHP-GTK 5.2.5 - not as expected:
1243685972,5313 versus 1243685973,0305
substracted: 0,49922299385071
bcsubbed: 0.000000 //should be 499223
Resolved
My bad!
Just read the manual for bcxxxx() functions. The supplied arguments should be STRINGS, not floats!
But there is still a difference between PHP and PHP-GTK:
- PHP bcxxx takes both strings and floats (and probably integers) as arguments.
- PHP-GTK bcxxxx takes STRINGS ONLY!
Is this a bug?
So the solution is to convert the float to a string. Be careful, though, calling strval() on, for instance, 0.5, will change it to '0,5', depending on your locale. So you cannot supply it to bcsub without replacing the colon with a decimal point.
<?php
$a= strval(microtime(true));
echo $a."\n"; // outputs 1243687944,9531 - notice the , colon, not the . decimal point
$a_str = str_replace(',', '.', $a);
echo $a_str; // 1243687944.9531 - this can be supplied to the bcmath function
?>
Here's the upper example corrected:
<?php
if (!function_exists('bcsub')) die('BC Math not present!');
$a = microtime(true);
usleep(0.5 * 1000000); //sleep for half a second
$b = microtime(true);
echo "$a versus $b\n"; // just checking if the values are correct
$substract = $b - $a; // substracting them manually
$a = str_replace(',' , '.' , strval($a));
$b = str_replace(',' , '.' , strval($b));
$bcsubstract = bcsub( $b, $a, 6);
echo "substracted: $substract\n".
"bcsubbed: $bcsubstract"; //just dumping the result
?>
Benchmark function
So here's the benchmark function, if anyone finds the need for it... Just put DA_benchmark('some marker'); anywhere in your code and watch the output. Usually you put it before and after some complex points in your script...
<?php
/**
* Simple marker benchmarking for php
*
* outputs 2 timings of the marker (in seconds)
* - one relative to the FIRST marker - usually start of script
* - other relative to the PREVIOUS marker
*
*
* @author author name <lex.non.scripta- nospam - gmail.com>
* @param string [$tag] the bench marker
* @param integer [$precision] the precision of the decimal - default 6
* @return void
*/
function DA_benchmark($tag, $precision=6){
static $last_bench, $start;
static $high = 0.0;
$a = microtime(true);
if (!$last_bench) $last_bench = $start = $a;
$time_in_script = bcsub(str_replace(',','.',strval($a)), str_replace(',','.',strval($start)), $precision);
$time_since_last = bcsub(str_replace(',','.',strval($a)), str_replace(',','.',strval($last_bench)), $precision);
$last_bench = $a;
echo "benchmark: @ $time_in_script # $time_since_last ";
if ( $time_since_last > $high ) { $high = $time_since_last; echo " **\t$tag"; }
else { echo " \t$tag"; }
echo "\n";
}
DA_benchmark('start of script');
sleep(2); /* or do some complex computing! */
DA_benchmark('this one took 2 seconds to complete - it\'s a high..');
sleep(3); /* some EVEN MORE complex computing */
DA_benchmark('this one took 3 seconds - another high!');
DA_benchmark('this one comes immediately after the previous - not a high');
?>