PHP ceil function strange behavior ? - php

Can somebody explain this ?
echo ceil( 20.7 * 100 ); // returns 2070
echo ceil( 2070 ); // returns 2070
all OK and logical, but
echo ceil( 40.7 * 100 ); // returns 4071
echo ceil( 4070 ); // returns 4070
not OK and not logical...
Why is this difference ?
Thanks

The wonderful world of floating point numbers:
printf("%.18f\n", 40.7*100);
//prints 4070.000000000000454747
printf("%.18f\n", 20.7*100);
//prints 2070.000000000000000000
In short: floating point numbers cannot represent all rational numbers exactly. In particular, neither 407/10 nor 207/10 can be represented exactly, and so the result of integer conversion always has an uncertainty of one unit.
The only rational numbers which can be represented exactly as binary floating point numbers are of the form "small odd integer times power of two", or in other words, those which have a small binary expansion.

Floating point errors. 40.7 cannot be represented exactly in a float. It'll be something like 40.700000001 or whatever. When you * 100 and ceil it, it rounds up to 4071.

Use arbitrary precision library bcmath e.g.:
ceil(bcmul(40.7, 100)); // 4070

Floating point numbers issue... you can overcome your problem with something like this:
echo ceil( (int) (40.7 * 100) );

You can overcome your problem with something like this:
$result = 40.7 * 100;
$result = (string) $result;
echo ceil($result);

Related

is possible to less float values..?

$quantity = 20;
$product_rate = 66.79;
$total = $quantity * $product_rate;
echo $total;
Output is showing 1335.8000000000002
is there possible to show 1335.8 using php..?
You can use the number_format() function like this:
$firstNum = 1335.8000000000002;
$number = number_format($firstNum, 1, '.', '');
echo $number;
outputs:
1335.8
more on number_format() here: http://php.net/number-format.
You can also multiply the number by 10, then use intval() to convert it to an integer (that way stripping out the decimals) and then divide by 10 like this:
$firstNum = 1335.8000000000002;
$number = 10 * intval($firstNum)/10;
echo $number;
outputs:
1335.8
Note: when using the methods above there will be no rounding, for rounding you would use something like this:
$number = round($firstNum, 1);
echo $number;
which in this case also outputs:
1335.8
Do you really use these variable values? I'm using PHP7 and the output for your given values is 1335.8. If you do a manual calculation it is the same result. It should be 1335.8. Anyway if you need to roundup the value you can use below.
round($total,1);
Please refer the below link and you will be able to grab more details.
http://php.net/manual/en/function.round.php
Because how floating point numbers work, they cannot represent every numbers exactly, so approximations are made.
The closest representation of 20 is 20, it can represent 20 exactly, but 66.79 for instance is approximated to 66.7900000000000062527760746889, that times 20 is 1335.800000000000125055521493778 that again cannot be represented and is approximated to 1335.80000000000018189894035459.
Depending on how you choose to print this number, it may round different ways, in your case for some reason you decided to print 13 decimal places so it rounded to 1335.8000000000002, but if you print only 1 or 2 decimal places it will print as 1335.8 or 1335.80. Just be mindful about that when printing floating point numbers, you may want to specify how many decimal places are relevant to you. For that, use number_format().
Example:
echo number_format($number, 2); // prints 2 decimal places
You can do this simply using echo echo round($total, 1) instead of doing round($total)

PHP. result of the subtraction of two floating point numbers

For example...
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
// result is:-1198.9699999988 not the -1198,97
But in this exampe:
$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
//Result is: 0.03
Why the difference in to examples? Lacks precision?
None of the numbers in your code can be expressed exactly in binary floating point. They have all been rounded somehow. The question is why one of the results has been (seemingly) rounded to two decimal digits and not the other. The answer lies in the difference between the precision and accuracy of floating point numbers and the precision PHP uses to print them.
Floating point numbers are represented by a significand (or mantissa) in the range [1, 2), which is scaled by multiplying it by a power of two. (This is what the "floating" in floating point means). The precision of the number is determined by the number of digits in the significand. The accuracy is determined by how many of those digits are actually correct. See: How are floating point numbers stored in memory? for more details.
When you echo floating point numbers in PHP, they are first converted to string using the precision configuration setting, which defaults to 14. (In Zend/zend_operators.c)
To see what is really going on, you have to print the numbers using a larger precision:
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
printf ("\$aa: %.20G\n", $aa);
printf ("\$bb: %.20G\n", $bb);
printf ("\$ab: %.20G\n\n", $ab);
$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
printf ("\$cc: %.20G\n", $cc);
printf ("\$dd: %.20G\n", $dd);
printf ("\$cd: %.20G\n", $cd);
Output:
$aa: 10694994.890000000596
$bb: 10696193.859999999404
$ab: -1198.9699999988079071
$cc: 0.89000000000000001332
$dd: 0.85999999999999998668
$cd: 0.030000000000000026645
The initial numbers have a precision of about 16 to 17 digits. When you subtract $aa-$bb, the first 4 digits cancel each other out. The result, (while still having a precision of about 16 to 17 digits), is now only accurate to about 12 digits. This lower accuracy shows up when the results is printed using a 14-digit precision.
The other subtraction ($cc-$dd) loses only a single digit of accuracy, which isn't noticable when printed with a 14-digit precision.
This should work for you:
(You have to round your result!)
$aa = 10694994.89;
$bb = 10696193.86;
echo $ab = round($aa - $bb, 2);

want to display exactly 2 digits after floating point

I want to convert floating value of 8 digits after floating point in to 2 digits after floating point ..
Eg. $a = 2.200000 ==> 2.20
I am using round function of php. Problem with round is if my number is 2.200000 it converts number in 2.2 . I want output as 2.20
Can any one suggest the possible way?
Actual code
$price = sprintf ("%.2f", round(($opt->price_value + ($opt->price_value * $this->row->prices[0]->taxes[0]->tax_rate)), 2));
i want out put like if my floating number is 2.2000000. then it should return me 2.20. but right now it is returning me 2.2
This does what I think you are asking for:
<?php
$a = 2.20032324;
$f = sprintf ("%.2f", $a);
echo "$a rounded to 2 decimal places is '$f'\n";
$a = 2.2000000;
$f = sprintf ("%.2f", $a);
echo "$a rounded to 2 decimal places is '$f'\n";
results:
[wally#lenovoR61 ~]$ php t.php
2.20032324 rounded to 2 decimal places is '2.20'
2.2 rounded to 2 decimal places is '2.20'
I added two test cases
i was working on it :D
$number='49.099998479854654656516198498465465465465';
function pure_decimal($number){
if(is_numeric($number) and floor($number)!=$number){
//decimal detected
$explode=explode('.',$number);
$first_no=$explode['0'];
$second_no=$explode['1'];
$get_only_two=substr($second_no,0,2);
$final_no=$first_no.'.'.$get_only_two;
$final_no=($final_no*1);
}else{
//normal
$final_no=$number;
}
return $final_no;
}
//result is 49.09
regards.
try $val = round($a * 100)/100;
Try the below code, You can get your result.
$a = 2.200000;
echo number_format((float)$a,2,'.','');

Abs() - issue with absolute value function in PHP

Can anyone explain why this code does this in regards to abs() (absolute value) -
In my code it will display 'GREATER' - although 0.50 is never GREATER than 0.5, am I missing out something here with the abs function?
$logic = abs(1.83333333333 - 2.33333333333); // 0.50
$limit = 0.50;
if ($logic > $limit) {
echo 'IS GREATER';
} else {
echo 'IS NOT GREATER';
}
Passing floating point numbers to abs you will get a floating point number as result. In that case you can experience problems with the floating point representation: a floating point is never absolutely precise, thus you are most likely getting a number that is not exactly 0.50 but something like 0.500000...01. You could try to round the result to the desired precision (in your case I guess it is two) with the php round function.
If you don't want to round as suggested by #Aldo's answer and your server supports the GMP math functions, you could use gmp_abs() instead. This way you don't run into PHP's inherent floating point problems.
Due to the way floating point math works, your absolute value $logic results in this value:
0.50000000000000022204
which is greater than 0.5
NB: above evaluated using Javascript which uses double precision math for all numbers:
Math.abs(1.83333333333 - 2.33333333333).toFixed(20)
Never compare floats by equality - user the epsilon technique instead PHP: Floating Point Numbers
define('EPSILON', 1.0e-8);
$logic = abs(1.83333333333 - 2.33333333333); // 0.50
$limit = 0.50;
$diff = $logic - $limit;
if (abs($diff) < EPSILON)
echo 'IS EQUAL';
else
echo 'IS NOT EQUAL';

Why does `intval(19.9 * 100)` equal `1989`?

Boy, this one is really weird. I expect the following code to print 1990, but it prints 1989!
$val = '$19.9';
$val = preg_replace('/[^\d.]/','',$val);
$val = intval($val * 100);
echo $val;
Why on earth is this happening?
Edit: and this code:
$val = '$19.9';
$val = preg_replace('/[^\d.]/','',$val);
echo $val . "<br>";
$val = $val * 100;
echo $val . "<br>";
$val = intval($val);
echo $val;
Prints:
19.9
1990
1989
Why does intval(1990) equal 1989???
This is a precision issue inherent to floating point numbers in PHP, and lots of other languages. This bug report discusses it a bit, in the context of casting as an int:
http://bugs.php.net/bug.php?id=33731
Try round($val * 100) instead.
The usual answer to this kind of question is to read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Why does intval(1990) equal 1989???
Because you're not taking intval(1990). You're taking intval($val * 100) where $val is a number close to, but slightly smaller than, 19.9.
Read The Floating-Point Guide to understand why this is so.
As for how to fix it: don't ever use floating-point values for money. In PHP, you should use BCMath instead.
i was facing similar issue with my code but got solution php.net
need to convert variable to string for intval operation e.g:
intval( 9.62 * 100 ) //gives 961
intval( strval( 9.62 * 100 ) ) //gives 962
$val is a floating point number - the result of "19.9" * 100. Floating point numbers are not 100% accurate in any language (this is by design). If you need 100% decimal accuracy for dollar values, you should use integers and perform all calculations using cents (E.g., "$19.90" should be 1990).

Categories