High precision calculation of PHP

Time:2021-2-4

PHPer, who is engaged in the financial industry, has frequent capital calculation. If you don’t pay attention, the user’s capital may lose hundreds of thousands, or even more terrible

javascript

Why is 0.1 + 0.2 not equal to 0.3? (correct result: 0.3000000000000004)

Why is 0.8 * 7 not equal to 5.6? (correct result: 5.600000000005)

PHP

var_dump(intval(0.58 * 100));

The correct result is 57, not 58

The trouble of floating point operation

In fact, these results are not language bugs, but they are related to the implementation principle of the language. All numbers in JS are unified as number, including shaping. In fact, they are all double types.

PHP distinguishes between int and float. No matter what language, as long as floating-point operations are involved, there are similar problems, we must pay attention to the use.

Note: if you use + - * / of PHP to calculate floating-point numbers, you may encounter some problems of wrong calculation results, such as echo intval (0.58 * 100) above; 57 will be printed instead of 58, which is actually a bug that the underlying binary system of the computer can not accurately represent floating-point numbers. It is cross language, and I also encounter this problem with Python. So basically, most languages provide class libraries or function libraries for accurate calculation. For example, PHP has BC high-precision function library. Later, I will introduce some commonly used BC high-precision functions.

Let’s go back to 57, 58 above.

Why is the output 57? PHP bug?

To understand this reason, we need to know the representation of floating-point numbers (IEEE 754)

Floating point number, 64 bit length (double precision) as an example, will use 1-bit sign bit (E), 11 digit (q), 52 bit mantissa (m) (a total of 64 bits)

Sign bit: the highest bit represents the positive and negative of the data, 0 represents the positive number, and 1 represents the negative number.

Exponent bit: the power of data with the base of 2, and the exponent is represented by offset code

Mantissa: the significant number after the decimal point of data

The key point here is the binary representation of decimals. You can baidu about how to use binary representation of decimals. I will not repeat it here. The key point is to understand that 0.58 is an infinite value for binary representation (the following number omits the implied 1)

The binary representation of 0.58 is basically (52 bits): 00101011101011100001000011110101110000100110111110.57 is basically (52 bits): 00100011110101110000100100100110111110, and the binary representation of the two, if only calculated by these 52 bits, is as follows:http://www.111cn.net

As for the specific floating point multiplication of 0.58 * 100, we don’t consider it in detail. If you are interested, you can see the floating point. Let’s look at it vaguely in mind 0.58 * 100 = 57.999999999

If you look at it, it will be 57 naturally .

It can be seen that the key point of this problem is: “you seem to have finite decimals, but they are infinite in the binary representation of the computer.”

So, don’t think it’s a PHP bug any more, that’s it ..

The problem of inaccuracy exists in + – *% / of PHP floating-point type

Let’s continue with the code:

$a = 0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8); // false

The printed value is Boolean false

Why is this? The PHP manual has the following warning for floating point numbers:

  Warning

Floating point precision

Obviously, simple decimal fractions like 0.1 or 0.7 cannot be converted to internal binary format without losing a little bit of precision. This can lead to confusing results: for example, floor ((0.1 + 0.7) * 10) usually returns 7 instead of the expected 8, because the internal representation of the result is actually similar to 7.999999.

This is related to the fact that it is impossible to accurately express certain decimal fractions in finite digits. For example, one third of the decimal system becomes 0.3333333.

So never believe that floating-point results are accurate to the last digit, and never compare two floating-point numbers to see if they are equal. If higher precision is needed, any precision mathematical function or GMP function should be used

Then we should rewrite the above formula as

$a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8); // true

The commonly used high-precision functions are as follows:

Bcadd - add two high precision numbers

  Bccomp -- compares two high precision numbers and returns - 1, 0, 1

  Bcdiv -- divide two high precision numbers

  Bcmod -- finding high precision digital remainder

  Bcmul - multiply two high precision numbers

  Bcpow -- seeking high precision digital power

  Bcpowmod - high precision digital power and modulus, which is very commonly used in number theory

  Bcscale - configure the default decimal places, which is equivalent to "scale =" in Linux BC

  Bcsqrt -- finding the square root of high precision digit

  Bcsub - subtracting two high precision numbers

BC high precision function library includes: addition, comparison, division, subtraction, remainder, multiplication, Nth power, default number of decimal points, square. These functions are more useful when it comes to money calculation, such as the price calculation of e-commerce.

/**
  *Comparison of two high precision numbers
  * 
  * @access global
  * @param float $left
  * @param float $right
  *@ param int $scale to the exact number of decimal points
  * 
  *@ return int $left = = $right returns 0 | $left $right returns 1
  */
var_dump(bccomp($left=4.45, $right=5.54, 2));
// -1
  
 /**
  *Add two high precision numbers
  * 
  * @access global
  * @param float $left
  * @param float $right
  *@ param int $scale to the exact number of decimal points
  * 
  * @return string 
  */
var_dump(bcadd($left=1.0321456, $right=0.0243456, 2));
//1.05
 
  /**
  *Subtracting two high precision numbers
  * 
  * @access global
  * @param float $left
  * @param float $right
  *@ param int $scale to the exact number of decimal points
  * 
  * @return string 
  */
var_dump(bcsub($left=1.0321456, $right=3.0123456, 2));
//-1.98
  
 /**
  *Division of two high precision numbers
  * 
  * @access global
  * @param float $left
  * @param float $right
  *@ param int $scale to the exact number of decimal points
  * 
  * @return string 
  */
var_dump(bcdiv($left=6, $right=5, 2));
//1.20
 
 /**
  *Multiplication of two high precision numbers
  * 
  * @access global
  * @param float $left
  * @param float $right
  *@ param int $scale to the exact number of decimal points
  * 
  * @return string 
  */
var_dump(bcmul($left=3.1415926, $right=2.4569874566, 2));
//7.71
 
 /**
  *Set the number of decimal places of BC function
  * 
  * @access global
  *@ param int $scale to the exact number of decimal points
  * 
  * @return void 
  */ 
bcscale(3);
var_dump(bcdiv('105', '6.55957')); 
//php7.1 16

Packaging method:

/**

 *Exact addition

 * @param [type] $a [description]

 * @param [type] $b [description]

 */

function math_add($a,$b,$scale = '2') {

  return bcadd($a,$b,$scale);

}

/**

 *Exact subtraction

 * @param [type] $a [description]

 * @param [type] $b [description]

 */

function math_sub($a,$b,$scale = '2') {

  return bcsub($a,$b,$scale);

}

/**

 *Exact multiplication

 * @param [type] $a [description]

 * @param [type] $b [description]

 */

function math_mul($a,$b,$scale = '2') {

  return bcmul($a,$b,$scale);

}

/**

 *Precise division

 * @param [type] $a [description]

 * @param [type] $b [description]

 */

function math_p($a,$b,$scale = '2') {

  return bcp($a,$b,$scale);

}

/**

 *Exact complement / modulus

 * @param [type] $a [description]

 * @param [type] $b [description]

 */

function math_mod($a,$b) {

  return bcmod($a,$b);

}

/**

 *Compare size

 * @param [type] $a [description]

 * @param [type] $b [description]

 *Greater than return 1 is equal to return 0 and less than return - 1

 */

function math_comp($a,$b,$scale = '5') {

  Return bccomp ($a, $B, $scale); // compare to decimal places

}

For those interested in PHP back-end technology and PHP architecture technology, my official group is 1023755567Click here Learn together and discuss with each other.
There is already management in the group to sort out the knowledge system (source code, learning video and other materials). You are welcome to get it for free.

 

 

PHP advanced learning mind map, interview; free access to documents and video resources