This question already has answers here:
php, var_export fails with float [duplicate]
(1 answer)
Is floating point math broken?
(31 answers)
Float / Float = strange result
(2 answers)
Closed 2 years ago.
Can someone explain what is happening here? I have floating point number that is to be rounded to two decimal points (price).
echo $total . " is rounded to " . round((float)$total,2);
var_export((float)$total);
echo " is rounded to ";
var_export(round((float)$total,2));
echo "\r\n";
Output is:
79.95 is rounded to 79.95
79.9500000000000028421709430404007434844970703125 is rounded to 79.9500000000000028421709430404007434844970703125
So, "echo" rounds to itself. When I use var_export() to output data, seem that round() is not working.
Just for test, I made:
$total = 79.9501234576908988888;
Then I get:
79.950123457691 is rounded to 79.95
79.9501234576908927920158021152019500732421875 is rounded to 79.9500000000000028421709430404007434844970703125
So, "echo" seem to automatically round floats to 11 decimal points. Why round() is not working with var_export is a mystery.
Does anyone have an explanation?
Thanks,
Rudolf
Floating point numbers have specific, limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16.
In your case, if you use var_export, it will output (or return) a parsable string representation of a variable, which in this case will also return all the data when your data is stored as a float variable.
That's why when you execute the following
var_export(round((float)$total,2));
The system will first round up the $total to 79.95, but since you have specified the float cast, it will store it to the system's data precision and so when you use the var_export to faithfully return the data, it will give you something like
79.9500000000000028421709430404007434844970703125
On the other hand, the PHP var_export function is intelligent enough to distinguish the type of data you are trying to parse. (even if you do not use the float cast). Hence if you parse "79", the value will be regarded as an integer, if you parse "79.123", the value will be regarded as float.
Say for the following codes:
<?php
//$total = 79.9501234576908988888;
$total = 79;
echo "parsing 79";
echo "<br>";
var_export((float)$total);
echo " is rounded to ";
var_export(round((float)$total,2));
echo "<br><br>";
$total = 79.123;
echo "parsing 79.123";
echo "<br>";
var_export($total);
echo " is rounded to ";
var_export(round($total,2));
echo "<br><br>";
?>
The result will be :
parsing 79
79 is rounded to 79
parsing 79.123
79.1230000000000046611603465862572193145751953125 is rounded to 79.1200000000000045474735088646411895751953125
How var_export () is rounded depends on the PHP version and the system setting 'serialize_precision'. You can display the setting with:
var_dump(ini_get('serialize_precision'));
If your rights allow you can with
ini_set('serialize_precision',"-1");
change this. "-1" means that an enhanced algorithm for rounding such numbers will be used.
The instruction must always be at the beginning of your script or you can change the setting in your php.ini.
Related
I know the question is very basic but it seems nothing working for me.
I have a number (either or float or integer) which I want to be formatted upto two decimal point. For this purpose I'm using PHP function number_format but it converts my number to string.
To convert it back to float I am using (float) or floatval(). But these functions just truncates the number after converting it to float from string.
Here is my code
$revenue_sum = array_sum(array_column($val2, 'weighted_revenue')); //23722
$test = number_format($revenue_sum, 2); //"23,722.00"
$test = (float)number_format($revenue_sum, 2); //23.0
$test = floatval(number_format($revenue_sum, 2)); //23.0
I want the $test to be 23722.00 for the $revenue_sum = 23722
If $revenue_sum = 2372.2 the $test should be 2372.20
number_format() function can be used as follows:
echo number_format($revenue_sum, 2,'.',''); // will return 23722.00 for the $revenue_sum = 23722
You are trying to type cast with ',' value, it is truncating the string.
you can try this
<?php echo sprintf("%2.2f", 8900.258); ?>
which will output as
8900.26
If you assign a floating point value to a variable, then it is converted to an internal binary format (usually using IEEE 754). Not all possible values has an internal representation. So while scanning a text, the float is rounded to the nearest possible value. So for example 1.23 is rounded to 1.22999999999999998.
Because of the internal representation, there is no difference between 100 or 1e2 or 100.0 or 100.0000.
And when printing a floating point value without any formatting instruction, PHP guess a good format and rounding some digits. So 1.22999999999999 is displayed as 1.23(may varies on different systems).
In general: As long you are calculating, formatting doesn't matter. It is mostly the best, to ignore the decimal fragments on debugging. But when printing (=converting to text), use functions like format_number() or any of the printf() functions.
To be more pragmatic:
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
Am having an issue where PHP expands the float value e.g. 241.09 becomes 241.0899999999. The issue is, the expanded value is included in a signature, thus the expansion is causing my signature to have a mismatch when matching with the actual data which has the original unexpanded form. How do I prevent the rounding off? My code section is as below:
round(floatval($resultParams["AvailableFunds"]), 2)
Somehow, even after applying the round function, the expansion still occurs. How do I prevent that??
It's caused by the PHP Floating point precision:
Floating point numbers have limited precision.
A solution may be to use only integer, e.g. save the float 123.45 as 12345 and when you need to use display it divide it by 100 and pass it to the number_format function:
$myNumView = number_format($myNum/100, 2, '.', '')+0;
By doing this, number_format returns a string formatted as 1234567.89, then by doing +0 PHP converts it to float (due to the PHP Type Juggling) and removes the rightmost 0 in the decimal part of the number:
$a = '35';
$b = '-34.99';
echo $myNum = ($a + $b);
echo '<br>';
echo $myNumView = number_format($myNum, 4, '.', '')+0;
returns:
0.009999999999998
0.01
And also, why does you get AvailableFunds from a string with floatval? It seems that AvailableFunds is a string containing the amount of fund and other text. I think this is a bad implementation on how saving the fund amount. It's better to save the value as is in a dedicated field as float.
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
If I use (int) to convert a product between a float type variable and an integer, the result is not what I expect it to. Please see my code.
The expectation is that the result is 4090270, not 4090269
(int)(4090270.0) works correctly
$amount = 40902.70; // Same for 40902.20
$amount= (int)($amount*100);
echo $amount; /// Output : 4090269
Never cast an unknown fraction to integer, as this can sometimes lead to unexpected results.
According to PHP documentation
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....
See this reference.
Try like this.
$amount = 40902.70; // Same for 40902.20
$amounts= intval(strval($amount*100));;
echo $amounts;
Note: intval and int converts doubles to integers by truncating the fractional component of the number.
For more info check : reference
$test1 = intVal(1999);
$amount = 19.99 * 100;
$test2 = intVal($amount);
$test3 = intVal("$amount");
echo $test1 . "<br />\n";
echo $test2 . "<br />\n";
echo $test3 . "<br />\n";
expected output:
1999
1999
1999
actual output
1999
1998
1999
Appears to be a floating point issue, but the number 1999 is the only number that I was able to get to do this. 19.99 is the price of many things, and for our purpose we must pass it as 1999 instead of 19.99.
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
I have this simple substraction code:
<?php
$n1 = 257931.076;
$n2 = 257930;
echo $n1 - $n2;
?>
Why i got 1.0760000000009 instead of 1.076
Where did the 0000000009 came from? i need precise result and i don't want to use round() or number_format() because sometime i have more than 3 decimal, for example: 12345.678912, anyone know?
I have tried to use round() or number_format() but it only for fixed decimal point, not dynamic
As #GordonM perfectly explained it, you cannot expect exact results when using floating point values.
You can use a library such as brick/math to perform exact calculations on decimal numbers of any size:
use Brick\Math\BigDecimal;
$n1 = BigDecimal::of('257931.076'); // pass the number as a string to retain precision!
$n2 = 257930;
echo $n1->minus($n2); // 1.076
The library uses GMP or BCMath internally when available, but can work without these extensions as well (with a performance penalty).
For technical reasons that every programmer should be aware of, IEEE floating point numbers simply can't represent numbers precisely and will use the closest approximation they can when storing them (In fact the only fractions that can be stored perfectly have denominators that are powers of 2 (1/2, 1/4, 1/8, 1/16, etc. All other values are approximations). PHP has an ini value called "precision", which controls how many digits are considered significant WHEN OUTPUTTING floating point values. It defaults to 14, with any digits after that hidden.
However, the actual value stored may try to approximate the desired value with far more digits than that. If you change precision, you'll see what is really being stored.
php > $test = 0.1;
php > var_dump ($test);
php shell code:1:
double(0.1)
php > ini_set("precision", 100);
php > var_dump ($test);
php shell code:1:
double(0.1000000000000000055511151231257827021181583404541015625)
php > var_dump (0.25);
php shell code:1:
double(0.25)
php > var_dump (0.4);
php shell code:1:
double(0.40000000000000002220446049250313080847263336181640625)
What can you actually do about this? Not a great deal, this is just a consequence of how floating point works. You can try to avoid using floating point if you need exact values (for example when dealing with money amounts, store 3.99 as 399 pennies/cents instead of 3.99 pounds/dollars), or you can use the "bugnum" libraries that are available in PHP, GMP and BC_Math, but these are both tricky to use and have their own sets of gotchas. They can also be hard on storage and/or processor time. In most cases it's best to just live with it and be aware that when you're dealing with floating point you're not dealing with an exact representation.
This question already has answers here:
Compare floats in php
(17 answers)
Closed 8 years ago.
I am new to PHP and trying to perform a simple arithmetic addition and comparison. I have an array with some decimal values and after adding all the values, I am trying to compare it to 1. My array is:
$myArray=[0.2,0.7,0.1]
and my code is:
$sum=0;
foreach($myArray as $val){
$sum+=$val;
}
Here, the sum comes out to be 1. But when I compare it using the following code:
if($sum!=1)
{
echo "Good";
}
else
{
echo "Bad";
}
it echoes "Good".
However, when my array contains values 0.8 and 0.2, it echoes "Bad". Can anyone help me on this?
If you check the PHP docs on floating-point numbers: php.net/manual/en/language.types.float.php, there is a huge warning on the page.
"Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded."
Thus, you could get unexpected results such as 0.2 + 0.7 = 0.900000000001. It's simply because computers have a hard time representing decimals. Binary was really built for integers.
Careful in your logic; I think you meant if($sum == 1) echo "Good", etc. In that case, 0.2+0.7+0.1 would echo "Bad", because it's totally possible that 0.2+0.7+0.1 = 1.00000001 or 0.99999999. On the other hand, adding a smaller number of floats together decreases the error, so 0.8+0.2 is more precise than 0.2+0.7+0.1.