Learn any precision extension function in PHP

Time:2021-9-10

Today is the first extension of mathematics. For mathematical operation, it is nothing more than those various mathematical operations. Of course, mathematical operation is also one of the most basic and fundamental things in the development process of the whole program software. No matter what major you study, you will basically learn data structures and algorithms in the end, and the algorithm is actually studying how to use mathematics to optimize various sorting and search capabilities. PHP has prepared a lot of mathematical calculation functions for us at the bottom. Let’s learn it.

What is accuracy

On the issue of accuracy, many small partners who have worked in finance may not be unfamiliar. Especially the front-end students, if you execute 1.1 + 2.2 in JS, the results won’t be as you want. This comes to the storage of floating point numbers. We all know that in the program world, any data actually exists in the form of binary at the bottom. Floating point numbers, due to the existence of decimal points, are more complex in storage, so this kind of precision loss will often occur.

But many people will be surprised that the result of directly executing 1.1 + 2.2 in PHP is correct. It seems that there is no such problem of precision loss. Hehe, it can only be said that you are too young to simple. The problem of precision loss is not a language problem. Basically, all languages will have such problems, but in different forms.

BC precision operation

Let’s take a look at how the loss of precision in the PHP environment can be demonstrated.

$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

We define a variable $a, whose content is 0.58. At this time, we multiplied him directly by 100, and it seemed that there was no problem. But if we forcibly convert it to int type, there is a problem. It is 58. Why does it become 57?

In fact, after floating-point operation, the result is not 58, but 57.99999999999999. If we directly echo, it will go through string strong conversion, which will directly output 58. However, if it goes through int strong conversion, whether it is inval() or (int), it will be converted according to the rule of discarding decimals forced by int. So the result became 57.

Through direct echo, we often feel that there seems to be no loss of accuracy in PHP, but in fact, this problem really exists. In many cases, such as storing in the database or converting to JSON format, problems will be found. If you want to calculate accurately, you can use BC extension related functions, that is, the bcmul () function we demonstrated last. Its function is to multiply the first parameter by the second parameter, and the result obtained is also high-precision, that is, the result with accurate precision.

Next, let’s look at the accuracy of addition, subtraction, multiplication and division through the conversion of JSON format.

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;

Through this code, you should be able to clearly see whether the precision loss problem in PHP exists. json_ When encoding () converts data, it will convert according to the field type, so the accuracy problem will be obvious. This is also the reason why many students have no problem when calculating at the back end, but they will find that the data has accuracy problems when outputting it to the front end through JSON.

A1 ~ A6 is the content of our first test code. It is obvious that the result of using $a * 100 is really 57.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.

A7 and A8 are demonstrations of addition. In PHP, the result of 1.1 + 2.2 is actually the same as that in JS. The accuracy of addition can be handled through bcadd(). Similarly, A9 and A10 are the problems of subtraction. The high-precision calculation results of subtraction can be obtained through bcsub(). Bcdiv () is used to handle division. Note that these functions have a third parameter, which represents the number of decimal places to be reserved. We have reserved 10 decimal places in order to compare with the original calculation in case of loss of accuracy.

The remainder calculation of bcmod () corresponds to the function of the% calculation symbol. Under normal circumstances, it is normal that the result of 10% 2 is 0, but here we calculate 10% 2.1, and the result is 0. After using bcmod(), the result is 1, which is the correct result. Bcpow () is the calculation of the power, which corresponds to the pow () function in the ordinary function. Similarly, here, we have a precision problem with the power of 1.1 in the calculation of the ordinary function. Using bcpow (), we show that there is no precision exception for the 30 digit decimal. It should be noted here that if bcpow () specifies the number of decimal places, it will be displayed. Even if the calculation result has no decimal places, it will be displayed as 0. The other functions above will not do so, and will only be displayed when there are decimals.

Finally, the bcsqrt () function, that is, the quadratic root. The number with overflow is not found for our test. If there is a small partner who has used and found overflow, you can leave a message.

Comparison function

We have finished various precision calculation functions above. Next, 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

The bccomp () function is used to compare the precision according to the number of decimal places. Its return result is – 1 if parameter 1 is less than parameter 2, 0 if it is greater than or equal to 1. The third parameter determines which one the user compares. In this example, we can see that if only the third decimal place is compared, the results of 1.00001 and 1 are equal. If we compare them to the fifth decimal place, the difference will be reflected.

Set decimal point and 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

Bcscale() is the number of decimal places set globally. After this function is set, all functions described above will be subject to bcscale() if the third decimal place function is not written.

The function of bcpowmod() is the same as the test code in the second line, that is, bcpow() and then bcmod(). It has few usage scenarios, but it is easy to write.

summary

In addition to BC related calculation functions, today’s content also talks about the problem of accuracy, which exists in all kinds of languages. In fact, in our daily development, it is better to store data with decimal point such as amount in units of points. In other words, in the background, the saved and calculated data are integer data. When displayed in the front end, divide by 100 and keep two decimal places. This can greatly ensure that the accuracy of data will not be lost.

In addition, for references related to precision in PHP, you can see the instructions on brother bird’s blog in the second link below. Our example 0.58 * 100 is also an example from his blog.

Test code:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/7. Learn any precision extension function in PHP. PHP

Reference documents:

https://www.php.net/manual/zh/book.bc.php

https://www.laruence.com/2013/03/26/2884.html

Official account: hard core project manager

Add wechat / QQ friends: [xiaoyuezigonggong / 149844827] get free PHP and project management learning materials

Tiktok, official account, voice, headline search, hard core project manager.

Station B ID: 482780532