PHP if statement fails to validate on "!== 0" - php

How can the below be possible:
$varnum = 4;
if( $varnum/4 - floor($varnum/4) !== 0){
echo 'foo';
}
This echoes 'foo' on my server running PHP 5.1.6. If i change the operator to == I get the same results.
I have no idea why, but could it possibly be because "==" is "equals" and "!==" is "Not identical"? How then would I make them identical? I guess in javaScript I would "parseInt", but there is no such thing in PHP, right?

The reason this fails is because in PHP, the floor function returns a float, despite the fact that the value is always a whole number. You can see this in the documentation here: http://php.net/manual/en/function.floor.php
You're doing a fixed type comparison of that float to an integer zero, so the result is false, regardless of whether the value is actually zero.
To fix this, either:
cast the output of floor to an integer - either intval(float(...)) or (int)float(..)
use != instead of !==.
use 0.0 instead of just 0 to compare against.
In case you're wondering why floor() would return a float rather than an integer, it's because the input is a float. The float data type has a larger possible range than integer, and thus it is possible to call floor() on a value that would be too big to hold in an integer. Therefore it would not be safe for the function to return an integer; it returns a float instead so that it can guarantee the result will be correct.
It may seem odd at first glance, but hopefully that explains the logic behind it for you.

What is it you are trying to accomplish? If you are trying to see if $varnum is divisible by four then use modulus, so...
$varnum = 4;
if ($varnum % 4 != 0) {
echo "foo - $varnum is divisible by 4";
}
You original post should use '!=' versus '!==', like this:
$varnum = 4;
if( $varnum/4 - floor($varnum/4) != 0){
echo 'foo';
}

Related

PHP - Strange result when compare 2 float values

I am trying to compare 2 values in PHP.
My logic is:
I have a remaining amount (a)
I have a amount to be charged (b)
I calculate remaining to be by ( a - b )
After charge action I get the actual remaining value (c)
I compare the value I got in #3 with (c)
Even though the both are similar PHP says they are not equal.
Below given is my code (with filled values)
<?php
$remaining_amount_before_payment = "600";
$remaining_amount_after_payment = (float)$remaining_amount_before_payment - (float)"387.60";
$actual_remaining_amount_after_payment = "212.4";
echo "actual_remaining_amount_after_payment: {$actual_remaining_amount_after_payment} <br><br>";
echo "remaining_amount_after_payment: {$remaining_amount_after_payment} <br><br>";
var_dump( ((float)$actual_remaining_amount_after_payment) == ((float)$remaining_amount_after_payment) );?>
I type cast the values to float, but the var_dump returns FALSE.
Can anybody help me to find out why this is?
I am using PHP 5.6.
Thanks in advance!
Bingo!
After several attempts I caught the catch. I was going crazy.
The "problem" is inside the right rounding values
$remaining_amount_before_payment = floatval("600"); // use floatval istead of (float)
$remaining_amount_after_payment = round($remaining_amount_before_payment - floatval("387.60"), 2);// use floatval istead of (float) and round result
$actual_remaining_amount_after_payment = floatval("212.4");// use floatval
echo "actual_remaining_amount_after_payment: {$actual_remaining_amount_after_payment} <br><br>";
echo "remaining_amount_after_payment: {$remaining_amount_after_payment} <br><br>";
var_dump( $actual_remaining_amount_after_payment === $remaining_amount_after_payment ); // return TRUE
Example
VoilĂ !
Use var_dump(abs(floatval($actual_remaining_amount_after_payment) == floatval($remaining_amount_after_payment)) == 0);
acual your variable '$remaining_amount_after_payment' is not realy 212.4
use a var_export to determine its value.
In my concern, You should "round" your floats values to a precision. round(x, precision) for comparison

unable to determine if a string is currently an integer or not

The following funciton drove me nuts. How on earth 100x could be equal to 100 and then 100x is reported as an integer?
For the life of me, I cannot figure it out.
You can copy and paste the whole thing and see it for yourself.
I'm missing a simple point somewhere here, help me out guys.
function blp_int($val) {
$orgval = $val;
$num = (int)$val;
echo "<li><font color=red>val: ". $val . " is being checked to see if it's an integer or not";
echo "<li><font color=red>orgval: ". $orgval ;
echo "<li><font color=red>num: ". $num ;
if ($orgval==$num) {
echo "<li><font color=red><b>YES IT IS! the [{$orgval}] is equal to [{$num}]</b>";
return true;
}
return false;
}
if (blp_int("100"))
{
echo "<h1>100 is an integer!</h1>";
}
else
{
echo "<h1>100 is NOT an integer!</h1>";
}
if (blp_int("100x"))
{
echo "<h1>100x is an integer!</h1>";
}
else
{
echo "<h1>100x is NOT an integer!</h1>";
}
the above code, when run returns the following;
val: 100 is being checked to see if it's an integer or not
orgval: 100
num: 100
YES IT IS. the [100] is equal to [100]
100 is an integer!
val: 100x is being checked to see if it's an integer or not
orgval: 100x
num: 100
YES IT IS. the [100x] is equal to [100]
100x is an integer!
I can remedy the situation by adding the following bits
if (!is_numeric($val))
{
return false;
}
to the top of the blp_int function right off the bat but,.. I'm still super curious to find out why on earth php thinks 100x=100 are equals.
As you can see in this example, casting 100x as an integer converts it to 100. Since you are not using strict comparison, '100x' == 100 is true. PHP removes the x from it to make just 100.
You could use strict comparison (which also compares the types), such that '100x' === 100 would return false. Using it, any time a string was compared to an integer, it would return false.
As per your edit: is_numeric may not be the most reliable, as it will return true for numbers formatted as a string, such as '100'. If you want the number to be an integer (and never a string), you could use is_integer instead. I'm not quite sure what exactly you're doing, but i thought I'd add this note.
I think you should use three equal signs in your IF:
if ($orgval===$num) {
Otherwise PHP casts the value 100x to 100 and 100=100.
Documentation: Comparison Operators
What kind of check do you want to do? There are a few ways you could go about it:
if (preg_match('!^[0-9]+$!', $input))
if (intval($input) == $input)
if (intval($input) === $input)
if ('x'.intval($input) === 'x'.$input)
It depends on how closely you want to check if it's an integer. Does it matter if you need to trim() it first?
Either cast it to an int or try http://php.net/manual/en/function.ctype-digit.php. You also need === in your if.

Issue with float multiplication and evaluation

This problem is best expressed in code:
$var1 = 286.46; // user input data
$var2 = 3646; // user input data
$var3 = 25000; // minumum amount allowed
$var4 = ($var1 * 100) - $var2; // = 250000
if ($var4 < $var3) { // if 250000 < 250000
print 'This returns!';
}
var_dump($var4) outputs: float(25000) and when cast to int, outputs: int(24999) - and thereby lies the problem.
I don't really know what to do about it though. The issue occurs upon multiplication by 100, and while there are little tricks I can do to get around that (such as *10*10) I'd like to know if there's a 'real' solution to this problem.
Thanks :)
This is a horrible hacky solution and I slightly hate myself for it, but this gives the expected behaviour:
<?php
$var1 = 286.46; // user input data
$var2 = 3646; // user input data
$var3 = 25000; // minumum amount allowed
$var4 = ($var1 * 100) - $var2; // = 250000
if ((string) $var4 < (string) $var3) { // if 250000 < 250000
print 'This returns!';
}
Cast them to strings, and they get converted back to int/float as appropriate for the comparison. I don't like it but it does work.
Really you need BC Math for precise floating point mathematics in PHP.
Its always a good idea to use ceil (or floor based on what you want) when using float number as int
In your case try ceil($var4) before comparison!
That's what floats do sometimes, it is all due to how floats are unable to precisely represent integers from time to time.
Instead of casting it to an int, you can round the number to an integer value and then cast it to an int. (possibly that cast unnecessary, but PHP isn't to clear about how such things happen internally, and even if you know how they happen right now, they may not in the future.
I think you could use bccomp for comparing floating point values but i think it's a function that's not in the PHP Core.
Otherwise i found this function here but i couldn't test it to see if it works
function Comp($Num1,$Num2,$Scale=null) {
// check if they're valid positive numbers, extract the whole numbers and decimals
if(!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num1,$Tmp1)||
!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num2,$Tmp2)) return('0');
// remove leading zeroes from whole numbers
$Num1=ltrim($Tmp1[1],'0');
$Num2=ltrim($Tmp2[1],'0');
// first, we can just check the lengths of the numbers, this can help save processing time
// if $Num1 is longer than $Num2, return 1.. vice versa with the next step.
if(strlen($Num1)>strlen($Num2)) return(1);
else {
if(strlen($Num1)<strlen($Num2)) return(-1);
// if the two numbers are of equal length, we check digit-by-digit
else {
// remove ending zeroes from decimals and remove point
$Dec1=isset($Tmp1[2])?rtrim(substr($Tmp1[2],1),'0'):'';
$Dec2=isset($Tmp2[2])?rtrim(substr($Tmp2[2],1),'0'):'';
// if the user defined $Scale, then make sure we use that only
if($Scale!=null) {
$Dec1=substr($Dec1,0,$Scale);
$Dec2=substr($Dec2,0,$Scale);
}
// calculate the longest length of decimals
$DLen=max(strlen($Dec1),strlen($Dec2));
// append the padded decimals onto the end of the whole numbers
$Num1.=str_pad($Dec1,$DLen,'0');
$Num2.=str_pad($Dec2,$DLen,'0');
// check digit-by-digit, if they have a difference, return 1 or -1 (greater/lower than)
for($i=0;$i<strlen($Num1);$i++) {
if((int)$Num1{$i}>(int)$Num2{$i}) return(1);
else
if((int)$Num1{$i}<(int)$Num2{$i}) return(-1);
}
// if the two numbers have no difference (they're the same).. return 0
return(0);
}
}
}
The problem is that floats just cannot represent some numbers. Since PHP doesn't have a "decimal" (or other fixed-point) type, you can basically only hack your way around these problems.
Assuming the first number in your example $var1 = 286.46 denotes some kind of money, you could just convert that to cents directly after the user entered it (e.g. through stripping the point and reading it as an integer) and thus calculate everything using integer math.
That's not a general solution - and I doubt that one exists (short of using arbitrary precision numbers, which some PHP extensions provide - but I that smells like overkill to me).

Less than operator not working correctly in PHP 5.3.1

For the purpose of the example, var 2 is preset from a database as "147.22" type STRING. var 1 is calculated previously in the script and has 147.22 type FLOAT.
Script:
<?
$var1 = (float)$var1;
$var2 = (float)$var2;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
My expected results would be that the script NOT echo "hello" since the two values are equal in amount and type.
However here is the output I'm getting:
float(197.22)
float(197.22)
hello
If I do not mess with the types and leave the one a float and the other a string, then it still does not work (this is how I got here in the first place).
If i force the values at the time of execution like this:
$var1 = 147.22;
$var2 = 147.22;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
I get this, (and it works):
float(197.22)
float(197.22)
Notice no "hello"....
Anyone have any clue wth is going on here?
If one of the floats is calculated numerically, and one is created from string assignment, they could be different. Try the following:
$x = 147.22;
$y = 147.2200000000001;
printf("%.40f\n", $x);
printf("%.40f\n", $y);
var_dump($x);
var_dump($y);
var_dump($x < $y);
outputs
147.2199999999999988631316227838397026062012
147.2200000000001125499693443998694419860840
float(147.22)
float(147.22)
bool(true)
Cast them to a string with a specified precision for comparison.
If you are dealing with floats, then it's not safe to compare them directly, because there may be rounding or representation issues.
You'd better to check if the difference between those numbers is less than some predefined and very minimal epsilon, and then determine if they're equal, or which is the greater one.
This discussion may be worth reading: Is casting to float destructive?
EDIT:
More discussions to read:
PHP: Floating point numbers
php integer and float comparison mismatch

Odd behavior comparing doubles, two PHP double values aren't equivalent

I have two seemingly equal double values in PHP (at least when echoing them).
But when comparing them with double equals, for some reason, it evaluates to false. Are there any special considerations when performing this kind of comparison?
You shouldn't compare floating point numbers using the == operator.
See the big warning and explanation in the php manual
What will work is asserting that the two numbers are within a certain small distance of each other like this:
if(abs($a - $b) < 0.0001) {
print("a is mostly equal to b");
}
The reason is because of rounding errors due to floating point arithmetic performed after the decimals are converted to binary, then converted back to decimal. These back and forth conversions cause the phenomenon where 0.1 + 0.2 does not equal 0.3.
float and double should never be compared for equality: there are precision errors that will make two numbers different even if they seem equal (when they are printed out, they are usually rounded).
Proper way to compare is using some DELTA constant:
define(DELTA, 0.00001); // Or whatever precision you require
if (abs($a-$b) < DELTA) {
// ...
}
Also note that this is not PHP specific but also important in other languages (Java, C, ...)
Representation of floating point numbers in PHP (as well as in C and many other languages) is inexact. Due to this fact, seemingly equal numbers can in fact be different and comparison will fail. Instead, choose some small number and check that the difference is less than that, like:
if(abs($a-$b)<0.00001) {
echo "Equal!";
}
See also explanations in the PHP manual.
A small function i made, hope helps someone:
function are_doubles_equal($double_1, $double_2, $decimal_count) {
if (!$decimal_count || $decimal_count < 0) {
return intval($double_1) == intval($double_2);
}
else {
$num_1 = (string) number_format($double_1, $decimal_count);
$num_2 = (string) number_format($double_2, $decimal_count);
return $num_1 == $num_2;
}
}
Usage:
$a = 2.2;
$b = 0.3 + 1.9002;
are_doubles_equal($a, $b, 1); // true : 2.2 == 2.2
are_doubles_equal($a, $b, 1); // false : 2.2000 == 2.2002
Not the fastest way but convert to string before comparing:
if( strval($a) === strval($b) ){
// double values are exactly equal
}

Categories