• 26 May 2013 - Since the new version attracted too many spammy registrations (around 250 fake accounts/day), user registrations are now protected by Mollom's spam protection service. Contact us if this causes some trouble.
  • 01 May 2013 - After the site upgrade, all passwords were reset and you will need to ask the site for a login reset on your first connection.

PHP GTK and BCMath functions (bcsub, bcadd, bccomp) not working properly

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');
?>

Darstellungsoptionen

Wählen Sie hier Ihre bevorzugte Anzeigeart für Kommentare und klicken Sie auf „Einstellungen speichern“ um die Änderungen zu übernehmen.