3

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 '.' 
 

enter image description here

The pattern where the PHP start to convert its real number into exponential number is : (see image below)

enter image description here

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 :

enter image description here

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):

enter image description here

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.
Lejiend
  • 1,219
  • 2
  • 16
  • 24
  • _“the pattern of PHP start to convert real number to exponential number”_ - PHP is not converting anything here _internally_, this is just the representation of such tiny numbers, when you output them in text form. – CBroe Mar 18 '21 at 12:37
  • At string value is not a number, but you are trying to treat it as such, and that appears to be the actual problem here. – CBroe Mar 18 '21 at 12:39
  • The real question here, how to make it working with bcmath, you can try on your environment, and you can copy exactly same code I written/screenshot above – Lejiend Mar 18 '21 at 12:39
  • You make it work, by working with actual numbers, and not string that contain stuff that _looks like_ numbers. – CBroe Mar 18 '21 at 12:40
  • brother, I work with both, actual number and string number, you can see and read thoroughly my screenshot and code. I tried both, not just one – Lejiend Mar 18 '21 at 12:41
  • yeah sorry about that, but I screenshot as a prove the error is really there, sorry if cannot upload that. but it is a prove the error really happening. I tried real number of exponential too, and it really throw this error – Lejiend Mar 18 '21 at 12:43
  • Is [this question](https://stackoverflow.com/questions/6876666/convert-float-to-string-in-php) of any help? – El_Vanja Mar 18 '21 at 12:47
  • 1
    @CBroe That last comment may have been a little harsh, as the code itself is present in the question alongside the screenshots. – El_Vanja Mar 18 '21 at 12:48
  • The error about the not well-formed value appears to get thrown from PHP 7.4 on only, https://3v4l.org/veQgt But that fixes itself, as soon as the number is actually provided as a string, https://3v4l.org/TEIaF – CBroe Mar 18 '21 at 12:58
  • I tried using normal float too, it throw this error. here a simple call to made on the php environment "bcadd(0.0000000254,4,12)" by calling this simple call, php will throw the same error as mine above, i ask here is to asking for a solution. – Lejiend Mar 18 '21 at 12:59
  • Have you checked the other question I linked to? About converting a float to a string representation. I believe it should clear your issue. – El_Vanja Mar 18 '21 at 13:00
  • Well the solution is obvious and trivial, provide the number as a string, as the manual says: `bcadd("0.0000000254",4,12);` The problem here appears to be that you expect this to accept `…E-05` in string form as a number, but it doesn’t. – CBroe Mar 18 '21 at 13:01
  • yeah now i can hardcode it to "0.0000000254", but when this value is totally calculated at different place and my function just accept its value as a exponential representation (beause calculation calculated at other place return in format of float and i received it), then I get this error – Lejiend Mar 18 '21 at 13:04

1 Answers1

12

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

See https://3v4l.org/SuWIu

iainn
  • 16,826
  • 9
  • 33
  • 40
  • 4
    When using number_format() you have to specify the fourth parameter $thousands_separator as an empty string: number_format($x, $precision, '.', ''). Otherwise a number greater 999 will produce the same error. – Andreas Bogavčić May 24 '22 at 15:53