Wrong Calculation? [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is double Multiplication Broken in .NET?
PHP unexpected result of float to int type cast
echo (int) ( (0.1+0.7) * 10);
Gives me answer 7 but not 8.
echo (int) ( (0.1+0.8) * 10);
Gives answer 9 which is right
whats wrong? can anybody explain
thanx,
-Navi

It’s normal – There’s a thing called precision while working with floating point numbers. It’s present in most of the modern languages. See here: http://www.mredkj.com/javascript/nfbasic2.html for more information.
((0.1+0.7) * 10) is probably something like 7.9999999 and (int) 7.9999999 = 7
On the other hand ((0.1+0.8) * 10) is probably 9.00000001 and (int)9.00000001 = 9
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....
So never trust floating number results to the last digit, and do not
compare floating point numbers directly for equality. If higher
precision is necessary, the arbitrary precision math functions and gmp
functions are available.
Source: http://php.net/manual/en/language.types.float.php

try
echo (float) ( (0.1+0.7) * 10);

Use Float
echo (float) ( (0.1+0.7) * 10);
it will give you perfect ans

try
echo (int) round( ( (0.1+0.7) * 10));
This should compensate the floating point computation error.

Related

floor(24.24*1e4) returns wrong value

Performing some coordinates rounding, I came to some bug or something, with different numbers it works as I needed
$res = floor(24.24*1e4)/1e4;
echo $res;
returns 24.2399
Do You know what is so special with this 242400, that it's returns 242399?
The problem is related to floating point precision
Even though the PHP manual says "Returns the next lowest integer value by rounding down value if necessary." if you read further down the page for "return values" in the PHP manual for floor() you'll see:
value rounded to the next lowest integer. The return value of floor()
is still of type float because the value range of float is usually
bigger than that of integer.
When we checkout float types we see a warning:
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.
Your error is due to float value, sometimes it happens.
Have you tried this?
$res = floor((int)(24.24*1e4))/1e4;
echo $res;
Or you can use round with an optional parameter to round up at a specific decimal.
For your example :
round($res, 4)

Weird PHP floating point behavior

Having weird problem:
$testTotal = 0;
foreach($completeBankArray as $bank){
var_dump($testTotal);
echo " + ";
var_dump(floatval($bank["amount"]));
echo " = ".(floatval($testTotal) + floatval($bank["amount"]))."</br>";
$testTotal = floatval(floatval($testTotal) + floatval($bank["amount"]));
And this is output I get:
------------------//--------------------
float(282486.09) + float(15) = 282501.09
float(282501.09) + float(3.49) = 282504.58
float(282504.58) + float(22.98) = 282527.55999999
float(282527.55999999) + float(5.2) = 282532.76
float(282532.76) + float(39.98) = 282572.73999999
float(282572.73999999) + float(2.6) = 282575.33999999
float(282575.33999999) + float(2.99) = 282578.32999999
------------------//-----------------------
How is this possible, what am I doing wring ?
You aren't doing anything wrong. Floats are notoriously innaccurate. From the docs (In the huge red warning box):
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....
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.
Floats are never exact and will diff quite a bit in the long run. If you are working with precision math, please read about the bc library.
Classic numeric precision example. Computers store floating point numbers in binary.
The short answer is that the computer cannot accurately represent some floating point numbers in binary.
The long answer involves moving between numerical bases. If you have a float, you cannot represent it completely in binary unless the denominator contains can be broken into factors that are powers of 2.
The other answers have given some insight into why you get this behaviour with floats.
If you are dealing with money, one solution to your problem would be to use integers instead of floats, and deal with cents instead of dollars. Then all you need to do is format your output to include the decimal.

MySQL & PHP decimal precision wrong

24151.40 - 31891.10 = -7739.699999999997
I grab these two numbers from a MySQL table with the type as decimal(14,2)
24151.40
31891.10
It is saved exactly as stated above and it echos exactly like that in PHP. But the minute I subtract the second value from the first value, I get a number -7739.699999999997 instead of -7,739.7. Why the extra precision? And where is it coming from?
From an article I wrote for Authorize.Net:
One plus one equals two, right? How about .2 plus 1.4 times 10? That equals 16, right? Not if you're doing the math with PHP (or most other programming languages):
echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!
This is due to how floating point numbers are handled internally. They are represented with a fixed number of decimal places and can result in numbers that do not add up quite like you expect. Internally our .2 plus 1.4 times 10 example computes to roughly 15.9999999998 or so. This kind of math is fine when working with numbers that do not have to be precise like percentages. But when working with money precision matters as a penny or a dollar missing here or there adds up quickly and no one likes being on the short end of any missing money.
The BC Math Solution
Fortunately PHP offers the BC Math extension which is "for arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings." In other words, you can do precise math with monetary values using this extension. The BC Math extension contains functions that allow you to perform the most common operations with precision including addition, subtraction, multiplication, and division.
A Better Example
Here's the same example as above but using the bcadd() function to do the math for us. It takes three parameters. The first two are the values we wish to add and the third is the number of decimal places we wish to be precise to. Since we're working with money we'll set the precision to be two decimal palces.
echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.
PHP doesn't have a decimal type like MySQL does, it uses floats; and floats are notorious for being inaccurate.
To cure this, look into number_format, e.g.:
echo number_format(24151.40 - 31891.10, 2, '.', '');
For more accurate number manipulation, you could also look at the math extensions of PHP:
http://www.php.net/manual/en/refs.math.php
This has to do with general float / double precision rates, which scientifically relates to 1.FRACTAL * 2^exponential power. Being that there's a prefix of 1, there's technically no such thing as zero, and the closest value you can obtain to 0 is 1.0 * 2 ^ -127 which is .000000[127 0s]00001
By rounding off your answer to a certain precision, the round factor will give you a more precise answer
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_round

Adding fractions number yields different result in PHP [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
PHP unexpected result of float to int type cast
int((0.1+0.7)*10) = 7 in several languages. How to prevent this?
Can someone explain me this???
<?php
echo (int) ((0.1 + 0.7)*10);//displays an output: `7`
?>
I was expecting to see 8 but I got 7 - please explain this behavior.
Is this a special feature from PHP? Or I didn't understand the integer type in PHP?
Thanks.
This question in php manual:
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....

PHP integer rounding problems

echo (int) ( (0.1+0.7) * 10 );
Why does the above output 7? I understand how PHP rounds towards 0, but isn't (0.1+0.7) * 10 evaluated as a float and then casted as an integer?
Thanks!
There's a loss in precision when decimals are converted internally to their binary equivalent. The computed value will be something like 7.9+ instead of the expected 8.
If you need a high degree of accuracy, use the GMP family of functions or the bcmath library.
See the manual:
http://php.net/manual/en/language.types.float.php
It is typical that simple decimal
fractions like 0.1 or 0.7 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.9.
The other answers explained WHY this happens. This should get you what you want:
echo (int) round( (0.1+0.7) * 10 );
Just round the float before casting it to an int.
I don't have php installed, but in python:
$ python
>>> 0.1+0.7
0.79999999999999993
>>>
Not all numbers in base 10 can be represented precisely in base 2 system. Check Wikipedia article:
http://en.wikipedia.org/wiki/Binary_numeral_system
section Fractions in Binary. In particular, this line:
Fraction Decimal Binary Fractional Approx.
1/10 0.1 0.000110011... 1/16+1/32+1/256...
1/10 cannot be represented in a finite way in base 2. Thus, 0.1 + 0.7 cannot be precisely calculated in base 2.
Never assume floating-point calculations are precise, it will bite you sooner or later.
1/10 cannot be represented in a finite number of binary digits, just like 1/3 cannot be represented as a finite number of base-10 digits. Therefore you are actually adding together 0.09999999999999... and 0.69999999999999... -- the sum is almost 8, but not quite.

Categories