双精度浮点转定点
When dealing with fixed point numbers, you have to be very careful – especially if you develop with PHP and MySQL. In this article, obstacles and subtleties of working with the PHP BCMath extension, MySQL fixed point expression handling and persisting fixed point data from PHP to MySQL are described. Despite the occurring barriers we try to figure out how to work with fixed point numbers and not to lose a digit.
处理定点数时,必须非常小心-特别是如果您使用PHP和MySQL开发。 在本文中,描述了使用PHP BCMath扩展,MySQL定点表达式处理以及将定点数据从PHP保留到MySQL的障碍和精妙之处。 尽管存在障碍,我们仍尝试找出如何使用定点数而不丢失数字。
BCMath的麻烦 (Troubles with BCMath)
BCMath documentation says:
BCMath文档说:
For arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings.
对于任意精度数学,PHP提供了二进制计算器,该计算器支持任意大小和精度的数字,以string表示。
So BCMath function parameters should be represented as strings. Passing numeric values to bcmath
can lead to wrong results, the same precision loss as when we treat double value as string
因此,BCMath函数参数应表示为字符串。 将数值传递给bcmath
可能会导致错误的结果,与我们将double值视为字符串时的精度损失相同
情况1 (Case 1)
echo bcmul(776.210000, '100', 10) . PHP_EOL;
echo bcmul(776.211000, '100', 10) . PHP_EOL;
echo bcmul(776.210100, '100', 10) . PHP_EOL;
echo bcmul(50018850776.210000, '100', 10) . PHP_EOL;
echo bcmul(50018850776.211000, '100', 10) . PHP_EOL;
echo bcmul(50018850776.210100, '100', 10) . PHP_EOL;
Results are:
结果是:
77621.00
77621.100
77621.0100
5001885077621.00
5001885077621.100
5001885077621.00 //here we can see precision loss
Never pass numeric values to BCMath functions, only string values that represent numbers. Even when not dealing with floating points, BCMath can output strange results:
切勿将数字值传递给BCMath函数,仅将代表数字的字符串值传递给BCMath函数 。 即使不处理浮点,BCMath也会输出奇怪的结果:
情况二 (Case 2)
echo bcmul('10', 0.0001, 10) . PHP_EOL;
echo bcmul('10', 0.00001, 10) . PHP_EOL;
echo 10*0.00001 . PHP_EOL;
Results are:
结果是:
0.0010
0 // thats really strange!!!
0.0001
The reason for this is that BCMath converts its arguments to strings, and there are cases in which a number’s string representation has exponential notation.
原因是BCMath将其参数转换为字符串,并且在某些情况下,数字的字符串表示形式具有指数表示法。
情况3 (Case 3)
echo bcmul('10', '1e-4', 10) . PHP_EOL; //outputs 0 as well
PHP is a weakly typed language and in some cases you can’t control input in a strict way – you want to process as many reques