This is the 25th day of my participation in the August Genwen Challenge.More challenges in August

Today’s lesson is the first extension on mathematics. For mathematical operation, nothing more than those various mathematical operations, of course, the whole process of software development, mathematical operations is also the most basic one of the most fundamental things. No matter what your major is, you’re going to end up learning about data structures and algorithms, and algorithms are the study of how to use mathematics to optimize sorting and lookup capabilities. PHP has prepared a lot of mathematical functions for us at the bottom, so let’s go through them.

What is the precision problem

About the accuracy problem, may be a lot of financial partners are familiar. Especially for those of you on the front end, if you implement 1.1+2.2 in JS, you will not get the results you want. Which brings us to floating-point storage. As we all know, in the program world, any data actually exists in binary form at the bottom. Floating point numbers, which are more complicated to store because of the decimal point, often have this kind of loss of precision.

However, many people will be surprised to learn that the result of executing 1.1+2.2 directly in PHP is correct, as there seems to be no such loss of precision. Ha ha, that can only say you are too young to simple. The problem of accuracy loss is not a problem of any language, almost all languages have such problems, but the form of expression is not the same.

BC precision operation

Let’s take a look at how precision loss shows up in the PHP environment.

$a = 0.58;

echo $a * 100, PHP_EOL; / / 58
echo intval($a * 100), PHP_EOL; / / 57
echo (int) ($a * 100), PHP_EOL; / / 57
echo intval(bcmul($a.100)), PHP_EOL; / / 58
Copy the code

We define a variable, $a, whose content is 0.58. So if we just multiply it by 100, it looks like it’s okay. But if we force it to be an int, there’s a problem, why is it 57 when it’s 58?

In fact, the result is not 58, but 57.9999999999999999. If we echo it, it will be string strong, and this will print 58, but if we echo it, it will print 58. Both inval() and (int) are converted in accordance with the rules of abandoning decimals when int is strong. So this is going to be 57.

Using a direct echo often makes it seem like PHP doesn’t have a loss of precision, but it does. In many cases, such as storing in a database or converting to JSON format, you will find the problem. If you want to calculate exactly, you can use the BC extension function, which is the bcmul() function we demonstrated at the end. What it does is it multiplicates the first parameter by the second parameter, and it gives you high precision, which is the exact result.

Next we will look at the accuracy of addition, subtraction, multiplication and division in various cases through json format conversion.

echo json_encode([
    'a1'= >$a./ / "a1" : 0.58
    'a2'= >$a * 100./ / "a2" : 57.99999999999999
    'a3' => intval($a * 100), // "a3":57
    'a4' => floatval($a * 100), / / "a4" : 57.99999999999999
    'a5' => floatval($a), / / "a5" : 0.58
    'a6' => intval(bcmul($a.100)), // "a6":58

    'a7'= >1.1 + 2.2./ / "a7" : 3.3000000000000003
    'a8' => floatval(bcadd(1.1.2.2.10)), / / "a8" : 3.3

    'a9'= >2 - 1.1./ / "a9" : 0.8999999999999999
    'a10' => floatval(bcsub(2.1.1.10)), / / "" a10:0.9

    'a11' => floatval($a * 100 / 10), / / "a11" : 5.799999999999999
    'a12' => floatval(bcdiv($a * 100.10.10)), / / "a12" : 5.8

    'a13'= >10 % 2.1.// "a13":0
    'a14' => bcmod(10.2.1), // "a14":"1"

    'a15' => pow(1.1.2), / / "a15" : 1.2100000000000002
    'a16' => bcpow(1.1.2.30), / / "a16" : "1.210000000000000000000000000000"

    'a17' => sqrt(1.1), / / "a17" : 1.0488088481701516
    'a18' => bcsqrt(1.1.30), / / "a18" : "1.048808848170151546991453513679"

]), PHP_EOL;
Copy the code

With this code you should be able to see clearly whether there is a loss of precision in PHP. Json_encode () will convert data according to the type of fields, so the accuracy problem will be obvious, which is also the reason why many students will find the data accuracy problem when they have no problem in the back-end calculation through JSON output to the front end.

A1 ~a6 is the content of our first test code, and it is clear that using $a * 100 normally results in 57.9999999999999999.

In PHP, 1.1+2.2 is the same as in JS. Bcadd () can handle the accuracy of addition. Similarly, a9 and a10 are subtraction problems, and high-precision calculation results of subtraction can be obtained by bcSub (). Bcdiv () is used to handle division. Note that each of these functions takes a third argument, which is the number of decimal places to reserve. We gave 10 decimal places to reserve, so that we can compare it to the original calculation if we lose precision.

The remainder of bcmod() is computed, and the corresponding % is computed. Normally, 10% 2 would be 0, but here we calculate 10% 2.1 would also be 0, and after bcmod() it would be 1, which is the correct result. Bcpow () is the calculation of the power, corresponding to the pow() function in the ordinary function, also here we have a precision problem in the calculation of the ordinary function 1.1 ^ 2, using bcpow() we display 30 decimal places also found no accuracy anomaly. Note that bcpow() will display all zeros if it specifies the number of decimal places, even if the result has no decimal places. The other functions do not, and only show up if they do have decimals.

BCSQRT () = BCSQRT () = BCSQRT () = BCSQRT

The comparison function

Having said that, let’s look at the problem of numerical comparison.

echo bccomp(1.2), PHP_EOL;   // -1
echo bccomp(1.00001.1.3), PHP_EOL; / / 0
echo bccomp(1.00001.1.5), PHP_EOL; / / 1
Copy the code

The bccomp() function is used to compare precision in terms of decimal places. It returns -1 if argument 1 is less than argument 2, 0 if argument 1 is greater than argument 2. The third parameter the user determines which digit to compare to. In this example, we can see that 1.00001 and 1 are equal if only the third decimal place is compared. The difference becomes apparent when you go to the fifth decimal place.

Set the decimal point and the BCpowmod function

Finally, let’s look at two more functions.

bcscale(30);
echo bcmod(bcpow(5.2), 2), PHP_EOL; / / 1.000000000000000000000000000000
echo bcpowmod(5.2.2), PHP_EOL; / / 1.000000000000000000000000000000
Copy the code

Bcscale () is the number of decimal points set globally. After setting this function, all of the functions described above will take bcScale () as set unless the third decimal number function is written.

The bcpowmod() function does exactly what the second line of test code does: bcpow() and bcmod(). It doesn’t have many uses, but it’s easy to write.

conclusion

In addition to bC-related computation functions, today’s content also covers the accuracy problem, which exists in all languages. In fact, to be honest, in our daily development, it is best to store data with decimal points, such as amounts, in units of units. That is, in the background, the data saved and computed is all integer data, in the front display, just divide 100 and leave two decimal places. This can greatly ensure that the accuracy of the data will not be lost.

Also, for a reference to accuracy issues in PHP, check out the birdman blog in the second link below. Our example 0.58 * 100 is also taken from his blog.

Test code:

Github.com/zhangyue050…

Reference Documents:

www.php.net/manual/zh/b…

www.laruence.com/2013/03/26/…

= = = = = = = = = = = = = = =

Follow the public account: [Hardcore project manager] to get the latest articles

Add WeChat/QQ friends: free xiaoyuezigonggong / 149844827 】 【 PHP, project management, learning materials

Zhihu, Public Account, Douyin, Toutiao Search [Hardcore Project Manager]

ID of station B: 482780532