If you are using PHP's +-*/to compute floating-point numbers, you may encounter problems with computed errors, such as Echo Intval (0.58*100), which prints 57 instead of 58, which is actually a bug where the computer's underlying binary cannot accurately represent floating-point numbers, which is cross-language. I also encountered this problem with Python. So basically most of the language provides a precise calculation of the class library or function library, such as PHP has a high precision library of BC, the following the PHP training teachers to introduce some commonly used high precision BC function.
Example
The code is as follows |
|
<?php $f = 0.58; Var_dump (Intval ($f * 100)); Why output 57?> |
Why is the output 57? A bug in PHP?
I believe that a lot of students have such a question, because there are a lot of people who ask me similar questions, not to mention Bugs.php.net often asked ...
To understand the reason, first we need to know the representation of floating-point numbers (IEEE 754):
The floating-point number, in 64-bit length (double precision), takes the 1-bit sign bit (E), the 11 exponent bit (Q), and the 52-bit mantissa (M) to represent (altogether 64 digits).
Sign bit: The highest digit indicates the positive or negative of the data, 0 indicates a positive number, and 1 is a negative number.
Digit: Represents the power of the data at a 2 base, and the exponent is represented by an offset code
Mantissa: A valid number that represents the decimal point of the data.
The key point here is that decimal in the binary representation, about decimal how to use binary, we can Baidu, I will not repeat here, we have to understand the key, 0.58 for binary representation, is an infinitely long value (the following number omitted the implied 1).
The binary representation of 0.58 basically (52 bits) is: 00101000111101011100001010001111010111000010100011110.57 The binary representation basically (52 bits) is: 001000111101011100001010001111010111000010100011110 and the two binary, if only through the 52-digit calculation, respectively: www.111cn.net
0.58-> 0.579999999999999960.57-> 0.5699999999999999 as to 0.58 * 100 of the specific floating-point number multiplication, we do not consider so thin, interested can see (floating point), We have a vague view of mental arithmetic ... 0.58 * 100 = 57.999999999
Then you intval, Nature is 57 ....
As you can see, the key point of this problem is: "You seem to have a poor decimal, in the computer binary representation is infinite."
So, do not think this is a PHP bug, this is the case ...
There is an inaccurate problem with PHP floating-point type in +-*%/
For example:
1.
$a = 0.1;
$b = 0.7;
Var_dump (($a + $b) = = 0.8);
The printed value is Boolean false
Why is that? The PHP manual has the following warning message for floating-point numbers:
Warning
Floating-point precision
Obviously a simple decimal score like 0.1 or 0.7 cannot be converted to an internal binary format without losing a little bit of precision. This can result in confusing results: for example, Floor (0.1+0.7) *10 usually returns 7 rather than the expected 8 because the internal representation of the result is actually similar to 7.9999999999 ....
This is related to the fact that it is impossible to accurately express certain decimal points with a finite number of digits. For example, the decimal 1/3 becomes 0.3333333. . .。
So never believe that floating-point numbers are accurate to the last one, and never compare two floating-point numbers for equality. If you do need higher precision, you should use arbitrary precision mathematical functions or GMP functions
The code is as follows |
|
<?php $a = 0.1; $b = 0.7; Var_dump (Bcadd ($a, $b, 2) = = 0.8); |
Bcadd-adds two high precision numbers
bccomp-compares two high-precision digits, returns-1, 0, 1
bcdiv-divides two high-precision digits
bcmod-to find high precision digit remainder
Bcmul-multiplies two high precision numbers
bcpow-to find high precision digital exponentiation
Bcpowmod-to seek high-precision digital exponentiation, the number theory is very common
bcscale-Configure the default decimal point number, which is equivalent to the "scale=" in Linux BC
bcsqrt-High precision Digital square root
bcsub-subtracts two high-precision digits
Sorted out some examples
PHP BC High Precision function library contains: Add, compare, divide, subtract, rest, multiply, n, configure the default number of decimal points, square. These functions are useful when it comes to calculating money, such as the price calculation of electricity dealers.
The code is as follows |
|
/**
* Two high precision number comparison
*
* @access Global
* @param float $left
* @param float $right
* @param int $scale The number of decimal places that are accurate to
*
* @return int $left = = $right return 0 | $left < $right back-1 | $left > $right return 1
*/
Var_dump (Bccomp ($left =4.45, $right = 5.54, 2));
//-1
/**
* Two High precision number addition
*
* @access Global
* @param float $left
* @param float $right
* @param int $scale The number of decimal places that are accurate to
*
* @return String
*/
Var_dump (Bcadd ($left =1.0321456, $right = 0.0243456, 2));
//1.04
/**
* Two high precision subtraction
*
* @access Global
* @param float $left
* @param float $right
* @param int $scale The number of decimal places that are accurate to
*
* @return String
*/
Var_dump (bcsub ($left =1.0321456, $right = 3.0123456, 2));
//-1.98
/**
* Two high-precision numbers by dividing
*
* @access Global
* @param float $left
* @param float $right
* @param int $scale The number of decimal places that are accurate to
*
* @return String
*/
Var_dump (Bcdiv ($left =6, $right = 5, 2));
//1.20
/**
* Two high precision number multiplication
*
* @access Global
* @param float $left
* @param float $right
* @param int $scale The number of decimal places that are accurate to
*
* @return String
*/
Var_dump (Bcmul ($left =3.1415926, $right = 2.4569874566, 2));
//7.71
/**
* Set the decimal digits of the BC function
*
* @access Global
* @param int $scale The number of decimal places that are accurate to
*
* @return void
*/
Bcscale (3);
var_dump (Bcdiv (' 105 ', ' 6.55957 '));
//16.007 |
Note: about the number of digits that are set, the excess is discarded rather than rounded.