I working on the few of the small decimals like 0.0000687, 0.0000063241, 0.0000454. I used BCMath as to get the most precise result because it involved with money calculation, so far BCMath it is very helpfull to me in fixing my previous bug that I faced. But I found that BCMath cannot work well if the exponential value that automatically converted by PHP is being passed to BCMath. Below is the sample code :
$x = 0.00002123; // let say I got this value from the other computation; // this $x value will automatically turn to exponential // value by php because it have few of leading 0 after the '.'
The pattern where the PHP start to convert its real number into exponential number is : (see image below)
As you can see from the image above, the pattern of PHP start to convert real number to exponential number is when the leading 0 number is 4 times -> 0.0000xxxxx (pattern where PHP start to convert to exponential).
Then, let say this variable $x will be calculate into one of PHP BCMath function :
# First, I work with float number $calculation1 = bcadd($x,5,12); // adding variable $x to 5 $calculation2 = bcmul($x,4,12); // multiply variable $x to 4 $calculation3 = bcdiv($x,5,12); // divide variable $x to 5 # Second, I tried to work with string number $y = (string) $x; $calculation4 = bcadd($y,5,12); $calculation5 = bcmul($y,4,12); $calculation6 = bcmul($y,4,12);
The result turn out to be error, here the screenshot for variable $x :
And here the result turn out to be error, here the screenshot for variable $y (pass to string first because BCMath works well working with string):
Important Note :
- So it turn out BCMath have problem when working with exponential value, I cannot avoid this exponential value because PHP will automatically parse it to exponential number when it reach its pattern (can see image I attach above).
- Considering where variable $x I get from different calculation, so in the real code, I cannot really hardcoded it to the way I want.
Advertisement
Answer
The bcmath functions in PHP work with numeric strings. Not floats and, importantly, not floats that have been cast to a string. This is mentioned in the extension’s introduction:
Valid (aka. well-formed) BCMath numbers are strings which match the regular expression
/^[+-]?[0]*[1-9]*[.]?[0-9]*$/
.
Casting a float to a string in PHP will often give you a result in scientific notation – the 2.123E-5
syntax you’re seeing in your results. bcmath cannot work with this representation; to match the regex above, the strings have to contain the argument in decimal form.
The warning you’re seeing was added in PHP 7.4, and is listed on the Backward Incompatible Changes page for that version. Previously any non well-formed arguments were silently interpreted as zero (which wasn’t exactly helpful).
As mentioned in the comments, the easiest way to convert a floating point number to its decimal form is with number_format
, supplying the same precision that you are already using for the bc functions:
$precision = 12; $x = 0.00002123; echo bcadd(number_format($x, $precision), 5, $precision);
5.000021230000