PHP 8.5.0 Beta 1 available for testing

Voting

: min(four, five)?
(Example: nine)

The Note You're Voting On

francois dot barbier at gmail dot com
16 years ago
As "benjcarson at digitaljunkies dot ca" (http://www.php.net/ref.bc.php#23038) noted in the first two comments, bcmath doesn't accept exponential notation.

Moreover, you might have other problems if you feed the bcmath functions directly with floating point numbers.
Consider the following example:
<?php
bcscale
(1);
$a = 0.8;
$b = 0.7;
var_dump((string) $a); // string(3) "0.8"
var_dump((string) $b); // string(3) "0.a"
var_dump(bcadd($a, $b)); // string(3) "1.5"
setLocale(LC_ALL, 'fr_BE.UTF-8');
var_dump((string) $a); // string(3) "0,8" --> note the comma
var_dump((string) $b); // string(3) "0,7" --> note the comma
var_dump(bcadd($a, $b)); // string(3) "0.0"
?>
The floating point numbers passed to the bcadd() function are automatically converted to string using the localized decimal separator. However, the bcmath functions always use a full stop, which results in the last result being incorrect.

Below is a function to convert floating point numbers to strings correctly. It takes care of the decimal separator and the exponential notation. It also preserve the precision without drifting away (e.g. 1.0 doesn't become 0.99999...)
<?php
/**
* Convert a number to locale independent string without E notation and without
* loosing precision
*
* @param int/float/double $fNumber The number to convert.
* @return string The locale independent converted number.
*/
function bcconv($fNumber)
{
$sAppend = '';
$iDecimals = ini_get('precision') - floor(log10(abs($fNumber)));
if (
0 > $iDecimals)
{
$fNumber *= pow(10, $iDecimals);
$sAppend = str_repeat('0', -$iDecimals);
$iDecimals = 0;
}
return
number_format($fNumber, $iDecimals, '.', '').$sAppend;
}
?>

Example:
<?php
setLocale
(LC_ALL, 'fr_BE.UTF-8'); // decimal separator is now a comma
$precision = ini_get('precision') + 2; // should give 16
bcscale($precision);
$big = pow(10, $precision);
$small = 1 / $big;
var_dump(bcconv($big + $small)); // string(17) "10000000000000000"
var_dump(bcadd($big, $small)); // string(18) "0.0000000000000000"
var_dump(bcadd(bcconv($big), bcconv($small))); // string(34) "10000000000000000.0000000000000001"
?>
The first result's precision loss is due to PHP's internal floating point numbers' representation.
The second result is wrong because of the localized decimal separator.
Finally, the last result is correct.

<< Back to user notes page

To Top