Set precision for a float number in PHP
You can use number_format()
to achieve this:
echo number_format((float) $number, $precision, '.', '');
This would convert 1518845.756789
to 1518845.757
.
But if you just want to cut off the number of decimal places short to 3, and not round, then you can do the following:
$number = intval($number * ($p = pow(10, $precision))) / $p;
It may look intimidating at first, but the concept is really simple. You have a number, you multiply it by 103 (it becomes 1518845756.789
), cast it to an integer so everything after the 3 decimal places is removed (becomes 1518845756
), and then divide the result by 103 (becomes 1518845.756
).
Demo
Set precision for floats in php for 15 numbers after comma
Ok I found answer for my question, which works as I wanted: ini_set('precision', 15);
Show a number to two decimal places
You can use number_format():
return number_format((float)$number, 2, '.', '');
Example:
$foo = "105";
echo number_format((float)$foo, 2, '.', ''); // Outputs -> 105.00
This function returns a string.
Can I rely on PHP php.ini precision workaround for floating point issue
Introduction
Floating-point arithmetic is considered an esoteric subject by many people. This is rather surprising because floating-point is ubiquitous in computer systems. Most fractional numbers don't have an exact representation as a binary fraction, so there is some rounding going on. A good start is What Every Computer Scientist Should Know About Floating-Point Arithmetic
Questions
Question 1
Can I rely on this solution if I need just precise 2 digits calculations (money)?
Answer 1
If you need need precise 2 digits then the answer is NO you can not use the php precision settings to ascertain a 2 digit decimal all the time even if you are not going to work on numbers higher than 10^6
.
During calculations there is possibility that the precision length can be increased if the length is less than 8
Question 2
If not can you provide me a clear example when this solutions fails?
Answer 2
ini_set('precision', 8); // your precision
$a = 5.88 ; // cost of 1kg
$q = 2.49 ;// User buys 2.49 kg
$b = $a * 0.01 ; // 10% Discount only on first kg ;
echo ($a * $q) - $b;
Output
14.5824 <---- not precise 2 digits calculations even if precision is 8
Question 3
Which php.ini.precision value suits best two digits, money calculations?
Answer 3
Precision and Money calculation are 2 different things ... it's not a good idea to use PHP precision for as a base for your financial calculations or floating point length
Simple Test
Lest Run some example together using bcmath
, number_format
and simple minus
Base
$a = 342349.23;
$b = 341765.07;
Example A
ini_set('precision', 20); // set to 20
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
Output
584.15999999997438863
584.15999999999996817 <----- Round having a party
584.16
584.15 <-------- here is 15 because precision value is 20
Example B
ini_set('precision', 14); // change to 14
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
Output
584.15999999997
584.16
584.16
584.16 <-------- at 14 it changed to 16
Example C
ini_set('precision', 6); // change to 6
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
Output
584.16
584.16
584.16
584.00 <--- at 6 it changed to 00
Example D
ini_set('precision', 3); // change to 3
echo $a - $b, PHP_EOL;
echo floatval(round($a - $b, 2)), PHP_EOL;
echo number_format($a - $b, 2), PHP_EOL;
echo bcsub($a, $b, 2), PHP_EOL;
Output
584
584
584.16 <-------------------------------- They only consistent value
0.00 <--- at 3 .. everything is gone
Conclusion
Forget about floating point and just calculate in cents
then later divided by 100
if that is too late just simply use number_format
it looks consistent to me .
Update
Question 1: Is precision workaround gonna fail for numbers between 0..999999.99, where A and B is a number with decimal places? If so please provide me an example
Form 0
to 999999.99
at increment of of 0.01
is about 99,999,999
the combination possibility of your loop is 9,999,999,800,000,000
I really don't think anyone would want to run such test for you.
Since floating point are binary numbers with finite precision trying to set precision
would have limited effect to ensure accuracy Here is a simple test :
ini_set('precision', 8);
$a = 0.19;
$b = 0.16;
$c = 0.01;
$d = 0.01;
$e = 0.01;
$f = 0.01;
$g = 0.01;
$h = $a + $b + $c + $d + $e + $f + $g;
echo "Total: " , $h , PHP_EOL;
$i = $h-$a;
$i = $i-$b;
$i = $i-$c;
$i = $i-$d;
$i = $i-$e;
$i = $i-$f;
$i = $i-$g;
echo $i , PHP_EOL;
Output
Total: 0.4
1.0408341E-17 <--- am sure you would expect 0.00 here ;
Try
echo round($i,2) , PHP_EOL;
echo number_format($i,2) , PHP_EOL;
Output
0
0.00 <------ still confirms number_format is most accurate to maintain 2 digit
Question 2: How to estimate/calculate when precision workaround fails? Without such crazy tests? Is there any mathematical*, straight answer for it? How to calculate is gonna to fail or not?
The fact sill remains Floating Point have Accuracy Problems but for mathematical solutions you can look at
- Machine precision and backward error analysis
- Minimizing the effect of accuracy problems
i don't need to know floating point calculations works, but when workaround fails if you know precision, and range of A and B
Not sure what that statement means :)
PHP - Floating Number Precision
Because floating point arithmetic != real number arithmetic. An illustration of the difference due to imprecision is, for some floats a
and b
, (a+b)-b != a
. This applies to any language using floats.
Since floating point are binary numbers with finite precision, there's a finite amount of representable numbers, which leads accuracy problems and surprises like this. Here's another interesting read: What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Back to your problem, basically there is no way to accurately represent 34.99 or 0.01 in binary (just like in decimal, 1/3 = 0.3333...), so approximations are used instead. To get around the problem, you can:
Use
round($result, 2)
on the result to round it to 2 decimal places.Use integers. If that's currency, say US dollars, then store $35.00 as 3500 and $34.99 as 3499, then divide the result by 100.
It's a pity that PHP doesn't have a decimal datatype like other languages do.
Using PHP floatval adds undesired trailing numbers behind decimal places
By using number_format will help to resolve your issue
<?php
$number = 8.800000000000001;
$precision = 1;
$number = intval($number * ($p = pow(10, $precision))) / $p;
echo number_format((float) $number, $precision, '.', '');
?>
php float calculation 2 decimal point
Try sprintf
("%.2f", $c);
Floating point numbers are represented in IEEE notation based on the powers of 2, so terminating decimal numbers may not be a terminating binary number, that's why you get the trailing digits.
As suggested by Variable Length Coder, if you know the precision you want and it doesn't change (e.g. when you're dealing with money) it might be better to just use fixed point numbers i.e. express the numbers as cents rather than dollars
$a = 3456;
$b = 3455;
$c = $b - $a;
sprintf ("%.2f", $c/100.0);
This way, you won't have any rounding errors if you do a lot of calculations before printing.
Default Number of Decimal Places to Output in PHP
And when you can't rely on the PHP configuration, don't forget about number_format() which you can use to define how a number is returned, ex:
// displays 3.14 as 3 and 4.00 as 4
print number_format($price, 0);
// display 4 as 4.00 and 1234.56 as 1,234.56 aka money style
print number_format($int, 2, ".", ",");
PS: and try to avoid using money_format(), as it won't work on Windows and some other boxes
PHP number more than 10 decimal places
Set precision higher at runtime
ini_set("precision", "16");
Also use (float)
instead of (double)
Related Topics
How to Send a Status Code in PHP, Without Maintaining an Array of Status Names
Subquery in Doctrine2 Notin Function
Jquery Ajax Returns the Whole Page
Trim Unicode Whitespace in PHP 5.2
_Construct() VS Sameasclassname() for Constructor in PHP
Laravel Error: Missing Required Parameters for Route
Ini_Set("Memory_Limit") in PHP 5.3.3 Is Not Working at All
Why Is Constructing Pdo Connection Slow
How to Prepare Statement for Update Query
Create an Encrypted Zip Archive with PHP
PHP Unexpected Result of Float to Int Type Cast
Remove Accents Without Using Iconv
PHP Syntax Question: What Does the Question Mark and Colon Mean
How to Assign PHP Variable Value to JavaScript Variable
Using If(Isset($_Post['Submit'])) to Not Display Echo When Script Is Open Is Not Working