Why this FALSE condition is TRUE? - php

Why this FALSE condition is TRUE?
<?php
if(111111111111111119 == 111111111111111118)
{
echo 'Condition is TRUE!';
}
?>

Quote from:
http://php.net/manual/en/language.operators.comparison.php
$a == $b is TRUE if $a is equal to $b after type juggling
If you compare a number with a string or the comparison involves
numerical strings, then each string is converted to a number and the
comparison performed numerically
So because your strings are both numeric they are being converted to numbers first.
Then on some architectures numbers are so big that are overflowing maximum integer size and you are getting equal results.

PHP DOC
Converting to string
An integer or float is converted to a string representing the number textually (including the exponent part for floats). Floating point numbers can be converted using exponential notation (4.1E+6).
Converting to integer
If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have enough precision to give an exact integer result. No warning, not even a notice will be issued when this happens!
My Guess you are using a 32 bits system so therefore
var_dump(111111111111111119,111111111111111118);
var_dump(111111111111111119 === 111111111111111118); // would be true on 32bit
Output
float 1.1111111111111E+17
float 1.1111111111111E+17
true
Simple Solution
if(bcsub("111111111111111119", "111111111111111118") == "0")
{
// 32 bit true
var_dump("Am Free");
}

since it's converted into a numeric value
if('111111111111111119' == '111111111111111118')
{
echo 'Condition is TRUE!';
} else {
echo 'Condition is FALSE!';
}
// on 64 bit: condition is FALSE! (tested on my mac)
I'd assume that on 32bit machine it'd be true. Even when i remove the quotes on my mac it's shows false.
if('a111111111111111119' == 'a111111111111111118')
{
echo 'Condition is TRUE!';
} else {
echo 'Condition is FALSE!';
}
// condition is FALSE!

Related

rand(0,$var) returns zero when $var is really big

When I run the code below:
<?
echo rand(0, 0xfffffffffffffbff);
echo rand(0, 0xfffffffffffffc00);
echo rand(0, $something_bigger_than_0xfffffffffffffbff);
I got something like:
-828
0
0
(the 2nd and 3rd number will always be zero)
mt_rand() has the same behavior.
so, why zero?
rand() function takes two integers as its arguments. Integers usually have the maximum range of 2^32. The supplied argument, when converted to integers, will be larger than this, hence causing an integer overflow.
This is actually documented behavior. From the PHP manual documentation:
When converting from float to integer, the number will be rounded
towards zero.
If the float is beyond the boundaries of integer (usually +/- 2.15e+9
= 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have
enough precision to give an exact integer result. No warning, not even
a notice will be issued when this happens!
You need to pass integer value to the rand() as the above $a = 0xfffffffffffffbff; is a double but not an integer value, the double value 0xfffffffffffffbff will be cast to an integer and eventually you will be getting a zero.
An illustration for your understanding.
<?php
$a = 0xfffffffffffffbff;
echo gettype($a); //"prints" double
if(is_int($a))
{
echo "Yes";
}
else
{
echo "Nope.. casting that to int results in..".intval($a)."<br>";
}
echo rand(0, $a);
OUTPUT :
double
Nope.. casting that to int results in..0
0

PHP XOR operation two numbers

I am trying to xor two values which are like below:
Variable 1 : 6463334891
Variable 2 : 1000212390
When i did xor with these values in php it gives me wrong answer.
It should give me "7426059853"
This is my code
$numericValue = (int)$numericValue;
$privateKey = (int)$privateKey;
echo "Type of variable 1 ".gettype($numericValue)."<br />";
echo "Type of variable 2 ".gettype($privateKey)."<br />";
$xor_val = (int)$numericValue ^ (int)$privateKey;
echo "XOR Value :".$xor_val."<br />";
Just a total stab into the dark...
You're doing this:
echo "6463334891" ^ "1000212390";
When you want to be doing this:
echo 6463334891 ^ 1000212390;
XOR is an operation on bytes. The byte representation of the integer 6463334891 and the string "6463334891" are very different. Hence this operation will result in very different values depending on whether the operands are strings or integers. If you get your numbers in string form, cast them to an int first:
echo (int)$var1 ^ (int)$var2;
That is because you re hitting the MAXIMUM INTEGER LIMIT which is 2147483647
From the PHP Docs...
The maximum value depends on the system. 32 bit systems have a maximum
signed integer range of -2147483648 to 2147483647. So for example on
such a system, intval('1000000000000') will return 2147483647. The
maximum signed integer value for 64 bit systems is
9223372036854775807.
Thus to handle such big integers you need to make use of an extension like (GMP) GNU Multiple Precision
<?php
$v1="6463334891";
$v2="1000212390";
$a = gmp_init($v1);
$b = gmp_init($v2);
echo gmp_intval($a) ^ gmp_intval($b); //"prints" 7426059853
Else , Switch to a 64-bit system.
my solution to maintain the value of big integers is to convert them to binary (with base_convert cause decbin doesnt work) and then make the xor for every bit, to finally convert the string to decimal.
function binxor($w1,$w2)
{
$x=base_convert($w1, 10, 2);
$y=base_convert($w2, 10, 2);
// adjust so both have same lenght
if (strlen($y)<strlen($x)) $y=str_repeat(0,strlen($x)-strlen($y)).$y;
if (strlen($x)<strlen($y)) $x=str_repeat(0,strlen($y)-strlen($x)).$x;
$x=str_split($x);$y=str_split($y);
$z="";
for ($k=0;$k<sizeof($x);$k++)
{
// xor bit a bit
$z.=(int)($x[$k])^(int)($y[$k]);
}
return base_convert($z,2,10);
}
Also, to adjust large numbers to 32 bits
bindec(decbin($number))
because decbin cuts the number to 32 automatically.

PHP: How to check if variable is a "large integer"

I need to check if a parameter (either string or int or float) is a "large" integer. By "large integer" I mean that it doesn't have decimal places and can exceed PHP_INT_MAX. It's used as msec timestamp, internally represented as float.
ctype_digit comes to mind but enforces string type. is_int as secondary check is limited to PHP_INT_MAX range and is_numeric will accept floats with decimal places which is what I don't want.
Is it safe to rely on something like this or is there a better method:
if (is_numeric($val) && $val == floor($val)) {
return (double) $val;
}
else ...
I recommend the binary calculator as it does not care about length and max bytes. It converts your "integer" to a binary string and does all calculations that way.
BC math lib is the only reliable way to do RSA key generation/encryption in PHP, and so it can easy handle your requirement:
$userNumber = '1233333333333333333333333333333333333333312412412412';
if (bccomp($userNumber, PHP_INT_MAX, 0) === 1) {
// $userNumber is greater than INT MAX
}
Third parameter is the number of floating digits.
So basically you want to check if a particular variable is integer-like?
function isInteger($var)
{
if (is_int($var)) {
// the most obvious test
return true;
} elseif (is_numeric($var)) {
// cast to string first
return ctype_digit((string)$var);
}
return false;
}
Note that using a floating point variable to keep large integers will lose precision and when big enough will turn into a fraction, e.g. 9.9999999999991E+36, which will obviously fail the above tests.
If the value exceeds INT_MAX on the given environment (32-bit or 64-bit), I would recommend using gmp instead and persist the numbers in a string format.
function isInteger($var)
{
if (is_int($var)) {
return true;
} elseif (is_numeric($var)) {
// will throw warning
if (!gmp_init($var)) {
return false;
} elseif (gmp_cmp($var, PHP_INT_MAX) >0) {
return true;
} else {
return floor($var) == $var;
}
}
return false;
}
I did
at the end of the function to check for numeric data.
return is_numeric($text)&&!(is_int(strpos($text,".",0)));
It will first check if it is numeric then check if there is no decimal in the string by checking if it found a position. If it did the returned position is an int so is_int() will catch it.
(strpos($text,".",0)==FALSE) would also work based on the strpos manual but sometimes the function seems to send nothing at all back like
echo (strpos($text,".",0));
could be nothing and the ==FALSE is needed.

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
}

What would be the best way to detect if a float has a zero fraction value (e.g. 125.00) in PHP?

See, I want to write a function that takes a float number parameter and rounds the float to the nearest currency value (a float with two decimal places) but if the float parameter has a zero fraction (that is, all zeroes behind the decimal place) then it returns the float as an integer (or i.e. truncates the decimal part since they're all zeroes anyways.).
However, I'm finding that I can't figure out how to determine if if a fraction has a zero fraction. I don't know if there's a PHP function that already does this. I've looked. The best I can think of is to convert the float number into an integer by casting it first and then subtract the integer part from the float and then check if the difference equals to zero or not.
if($value == round($value))
{
//no decimal, go ahead and truncate.
}
This example compares the value to itself, rounded to 0 decimal places. If the value rounded is the same as the value, you've got no decimal fraction. Plain and simple.
A little trick with PHPs type juggling abilities
if ($a == (int) $a) {
// $a has a zero fraction value
}
I think the best way:
if ((string)$value == (int)$value){
...
}
Example:
$value = 2.22 * 100;
var_dump($value == (int)$value); // false - WRONG!
var_dump($value == round($value)); // false - WRONG!
var_dump((string)$value == (int)$value); // true - OK!
function whatyouneed($number) {
$decimals = 2;
printf("%.".($number == (int)($number) ? '0' : $decimals)."F", $number);
}
So basically it's either printf("%.2F") if you want 2 decimals and printf("%.2F") if you want none.
Well, the problem is that floats aren't exact. Read here if you're interested in finding out why. What I would do is decide on a level of accuracy, for example, 3 decimal places, and base exactness on that. To do that, you multiply it by 1000, cast it to an int, and then check if $your_number % 1000==0.
$mynumber = round($mynumber *1000);
if ($mynumber % 1000==0)
{ isInt() }
Just so you know, you don't have to write a function to do that, there's already one that exists:
$roundedFloat = (float)number_format("1234.1264", 2, ".", ""); // 1234.13
If you want to keep the trailing .00, just omit the float cast (although it will return a string):
$roundedFloatStr = number_format("1234.000", 2, ".", ""); // 1234.00

Categories