This question already has answers here:
Why does `intval(19.9 * 100)` equal `1989`?
(5 answers)
Closed 4 years ago.
i am doing some calculation where i noticed intval weird behavior
which is making a whole lot of mess because i just want int part of whole variable but intval is stabbing me in the back in comparisons. Any ideas why its behaving like that and what i can use for my requirement?
intval( 9.62 * 100 ) //gives 961
(int)( 9.62 * 100 ) // gives 962.0
my tried methods to achieve my goals were:
floor(9.62 * 100) // but its giving 962.0 no acceptable
This should work for you.
intval(strval( 9.62 * 100));
It seems to be a problem with the precision of floating points, and converting the number to string and then to int seems to fix the problem.
Here is a link to the documentation, http://php.net/manual/en/language.types.float.php
As it states,
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....
echo intval((0.1 + 0.7) * 10); //returns 7
echo intval(strval(0.1 + 0.7) * 10); //returns 8
Since (int) always rounds the number down, a small error in the representation makes the cast round it one number down that you would otherwise expect.
I tried sprintf('%.40F', 9.62 * 100.0);, and get this: "961.9999999999998863131622783839702606201172".
Thats why intval( 9.62 * 100 ) gives you 961.
You can try to use bcmul()
(int) bcmul(9.62, 100);
Please try this
ceil(9.62*100);
Related
I need to round prices for my client in a non-common way :
120.28 => 120.2
130.23 => 130.2
150.64 => 150.6
The rule is to always keep the nearest lowest 1 precision.
I try to use the round() method but all my tries are useless since this method handle half which i have to ignore.
ceil() and floor() will not work out of the box.
Is a combination of those 3 methods would work ?
I think the solution
0.1 * intval(10 * $price) causes problems when prices are the result of calculations.
$price = 0.70 + 0.10; //0.80 expected
print_r(0.1 * intval(10 * $price)); //0.7
The following solution avoids this error by rounding to 2 decimal places and truncating using a string function.
$price = 0.70 + 0.10; //0.80 expected
$newPrice = substr(sprintf('%0.2f',$price),0,-1);
print_r($newPrice); //0.8
Demo: https://3v4l.org/hFjDL
phpHow about 0.1 * intval(10 * $price)?
What it does is multiply the price by 10, so 120.28 becomes 1202.8. Then it takes integer part using intval(), which is 1202, and then divides it by ten giving 120.2.
See: https://3v4l.org/3qMhd
I think the problem indicated by jspit is relevant, we could compensate for prices that are just a hair under their expected value. Something like this:
0.1 * (int)(10 * $price + 1E-6))
It works, see https://3v4l.org/5YCEu.
The value 1E-6 is chosen with care, not too much or too little.
floating points in PHP have roughly 16 digits of precision and money is usually not more than a few billion. Billions use 9 or 10 digits, subtract that from the 16 we have and you get the 6.
Also, 6 digits should be ample. If an amount is 10.599999 it will still be converted to 10.5. Only when it is even closer, say 10.5999999 will it become 10.6.
You may want to put this point somewhere else. You could decide that 10.555 should be 10.6. Then you choose a value of 0.45. See; https://3v4l.org/YWVI0. The point is that you can exactly choose where you want this point to be, no more surprises.
This question already has answers here:
Why does floating-point arithmetic not give exact results when adding decimal fractions?
(31 answers)
Closed 6 years ago.
I have been scratching my head at this VERY odd problem. I do some calculations in PHP and the end result is a number. This is a whole number, but because calculations are done, PHP considers this a float. However, when I typecast it as an integer, it magically gets subtracted one. As in 1. A whole integer down. I really am at a loss. Try for yourself.
<?php
$number_of_rows = 10;
$number_of_columns = 19;
$active = array();
$tile = 160;
$column = $tile/$number_of_columns; // 8.42105263158
$rounded_down = floor($column); // 8
$column = $column-$rounded_down; // 0.42105263158
$column = $column*$number_of_columns; // 8
var_dump($column); // 8 -> that is great
var_dump((int)$column); // 7 -> WTF?!!!
?>
PHP 7.0.12 on Linux 64 bit.
See the Warning in PHP manual for an explanation.
Excerpt that talks about precision and a floor() example:
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....
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
I found somewhere in book
echo (int) ((0.1 + 0.7) * 10);
output is : 7
echo ((0.1 + 0.7) * 10);
output : 8
why both out are different ? I think answer should be 8
When you write
echo ((0.1 + 0.7) * 10);
the result of this simple arithmetic
expression is stored internally as 7.999999 instead of 8.
Now when the value is converted to int,
echo (int) ((0.1 + 0.7) * 10); // 7.999999 when typecasted to int becomes 7
PHP simply truncates away the fractional part, resulting in a rather
significant error (12.5%, to be exact).
It's because float point at this scenario does not fit to memory and is truncated when converting to integer.
Read about that in PHP manual about float
Warning
Floating point precision
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.
Please check http://php.net/manual/en/language.types.integer.php and find this
Warning : Never cast an unknown fraction to integer, as this can sometimes lead to unexpected results.
<?php
echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>
See also the warning about float precision.
if I try to print
echo ((0.1 + 0.7) * 10);
output (http://codepad.org/m3mNNO77)
8
but if I try to print
echo (int)((0.1 + 0.7) * 10);
output (http://codepad.org/8OTCnlVG)
7
why two different results ?
If you perform the echo without the (int) cast, it resulits in:
echo ((0.1 + 0.7) * 10);
8
So what happens is that the floating point actually represents it as 7.99999....
When you perform an (int) cast, the default behavior is to take the integral part, so that's 7. Although it is extremely close to 8, it is not the behavior of a cast to round off.
The errors are due to the fact that floating point numbers are represented with a binary radix. Representing 0.8 correctly is thus impossible. Floating points round off the answers, and hope it doesn't bother that much. When you represent the floating point like 0.8, the result is 0.80000...
Proof of concept using the PHP interactive shell (php -a):
$ php -a
Interactive mode enabled
php > echo number_format(((0.1 + 0.7) * 10),20)."\n";
7.99999999999999911182
php > echo number_format(0.8,20);
0.80000000000000004441
As you may be aware, floating point math is not exact due to restrictions in their representation.
(0.1 + 0.7) * 10 works out to something like 7.99999999999....
When echo'd out, the number is converted to a string using rounding, which uses the php.ini precision setting (15 by default, I believe) to limit the number of decimal numbers. It happens that this rounding gives exactly 8.
However, (int) casts the float to an integer instead, and this is done with truncation. It doesn't matter how close to the next integer up you are, it will always round down. This is why you get 7 here.
I recently start to learn PHP.
<?php
echo (int) ( (0.1+0.7) * 10 ); // prints '7', why not '8' ?
?>
Please convince me of this type-conversion process.
From PHP.net
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.
This is due to the fact that it is impossible to express some fractions in decimal notation with a finite number of digits. For instance, 1/3 in decimal form becomes 0.3.
You are running into floating point inaccuracy.
0.1 + 0.7 is not exactly 0.8, but slightly less. The cast to int simply truncates the value and yields 7 as the result.
To get the correct result use rounding:
<?php
echo (int) round( (0.1+0.7) * 10 );
?>
From 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.
As others have said, it's due to a loss of precision, as revealed by:
<?php
printf("%30.27f\n", (0.1 + 0.7) );
printf("%d\n", (int) (0.1 + 0.7) );
printf("%30.27f\n", ( (0.1+0.7) * 10 ) );
printf("%d\n", (int) ((0.1 + 0.7) * 10) );
?>
which outputs:
0.799999999999999933386618522
0
7.999999999999999111821580300
7
You're probably seeing a floating point rounding error, and when you int() it, it goes from being 7...9 to 7.
I am not sure, but this is probably because the int cast is truncating.
.1 + .7 might result in .799999999999999999999999 and
multiplying this by 10 = 7.9999999999999999999
(int) truncates this to 7.