Why does “$temp = 0; echo ~$temp;” print -1? - php

Can anybody tell the internal procedure of the below code
<? $temp = 0; echo ~$temp; ?>
//instead of 1 it displays -1

echo ~$temp;
^bitwise not operator
Assuming 32-bit, Bitwise inverse of 0000 is FFFF (All 1's) which is -1, in signed int's case.
Another way to look at it: What ~ did is to give you the (One's complement)
In order to get the negative of a number, you take the 2's complement, which is just the
1's complement + 1
So,
(1's complement of 0) + 1 = 0 //negative 0 is 0
hence, 1's complement of 0 = -1

Bitwise-not (~):
This inverts each bit of its operand. If the operand is a floating point value, it is truncated to an integer prior to the calculation. If the operand is between 0 and 4294967295 (0xffffffff), it will be treated as an unsigned 32-bit value. Otherwise, it is treated as a signed 64-bit value
Its because you're actually dealing with a full 32-bit unsigned integer with NOT. What that means is you're not simply inverting 0001 but inverting 00000000000000000000000000000001
which becomes 11111111111111111111111111111110
essentially this is the number + 1 and negated. so 1 becomes -(num+1) which is -1 or
1111111111111111111111111111110
in binary (unsigned)
for example:-
$temp=1; echo~$temp; print -2 //-(n++)

Because ~0 is -1.
~ operator reverts every bit of 0.
The relation is: -$temp === ~$temp + 1

Related

PHP idiom for a counter over non-negative ints

In trying to make a counter that returns to 0 when the int range is exhausted. Essentially, 0, 1, ..., MAX_INT - 1, MAX_INT, 0, 1, ...
The idiomatic C is
x = ((x + 1) & MAX_INT);
But this won't work in PHP because the int gets promoted to a double when it overflows. The cleanest I can come up with is x = x == PHP_INT_MAX ? 0 : x + 1, but it's messier.
This seems to work:
$x = ($x + 1) % (PHP_INT_MAX+1);
You can use intval() to force using integers:
$x = intval($x + 1) & PHP_INT_MAX;
Try it out: echo intval(PHP_INT_MAX + 1): https://3v4l.org/7jlPN
Update:
The manual on Converting to integer states:
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 other than Windows), 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!
So you are right, while this is consistent for current implementations, the result is specified to be undefined and you should not rely on it.
That leaves you with more verbose solutions, either with % modulus or the ternary conditional as you already have it (which I would prefer for clarity and robustness).

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.

Odd and Even numbers (using & or %)

I've always used the following in order to find even and odd numbers:
if( $num % 2 ) { echo "odd"; }
if( !($num % 2) ) { echo "even"; }
But recently I stumbled upon with the following code that works exactly the same:
if( $num & 1 ) { echo "odd"; }
if( !($num & 1) ) { echo "even; }
What's the logic behind the "&" in the second method?
I went to check the PHP: Arithmetic Operators and the ampersand is not part of the options.
Thanks.
It is the bitwise-AND operator. Remember that in the computer, every integer is stored in binary form, and the lowest-significance binary digit is 2^0 == 1. So, every odd number will have the lowest binary digit = 1.
So, the bitwise AND operator compares your value bit-by-bit with the constant 1. Bits that are 1 in both operands are set to 1 in the result, but bits that are 0 in either operand are set to 0 in the result. The final result (which will be either 1 or 0) is coerced to boolean by PHP because you are using it as the clause in an if() statement.
There is a very good reason for checking evenness with & instead of %: Speed! The % operator requires a division operation so the remainder can be calculated, which is computationally much, much more expensive than just comparing the bits directly.
An example:
$num = 9; // 9 == 8 + 1 == 2^3 + 2^0 == 1001b
echo (string)($num & 1); // 1001b & 0001b = 0001b - prints '1'
$num = 10; // 10 == 8 + 2 == 2^3 + 2^1 == 1010b
echo (string)($num & 1); // 1010b & 0001b = 0000b - prints '0'
& is the binary AND.
The binary value of an odd number AND 1 will be 1, and the binary value of an even number AND 1 will be 0.
This happens because the binary value of an odd number always ends with 1 and the binary value of an even number ends with 0. So...
10101101 & 00000001 = 00000001 in the case of an odd number and,
10101100 & 00000000 = 00000000 in the case of an even number.

Pipe sign in PHP Code

I wanted to concatenate 2 variables, and by error I typed another code and I got a strange result.
This is what looks like the code :
echo 'Hello World' | 'test';
Result : |e|o World
What the pipe sign do if not concatenated ?
According to the PHP manual
"|" is a "bitwise OR". Bitwise operators allow evaluation and manipulation of specific bits within an integer.
Example Name Result
$a | $b Or (inclusive or) Bits that are set in either $a or $b are set.
Example:
$a = 9;
$b = 10;
echo $a | $b;
This would output the number 11 as follows:
1 Byte ( 8 bits )
Place Value 128 64 32 16 8 4 2 1
$a 0 0 0 0 1 0 0 1 = 9
$b 0 0 0 0 1 0 1 0 = 10
$a | $b 0 0 0 0 1 0 1 1 = 11
If you notice we have 3 bits set, in the 8, 2, and 1 column.. add those up 8+2+1 and you get 11.
For mere string concatenation use the dot . operator.
Hope that clarifies it.
It's the OR bitwise operator
If you want to concat string you should use dot
echo "ABC" . "DEF";
Example of OR bitwise usage
// base 16 - result in 0x03
$result = 0x01 | 0x02;
// base 2
0000 0001
0000 0010
---------
0000 0011
That | means 'bitwise OR', which will convert the strings into binary, then overlay them on each other to calculate the result using logical OR for each position i.e. if either string has a 1 at that position, then the result will have a 1, otherwise, you'll get a 0.
In this case, it's doing this with the numerical ascii character codes of each character, which sometimes leads to new character codes and sometimes to garbage, which won't render. This is why the beginning of 'Hello world' is messed up, where it is overlaid with 'test', but the end is fine because it's not having any 1s added to it by another string at that point. See here for a more detailed example from the manual (uses XOR, but same idea).
Use . for concatenation.
I would guess that it's a bitwise OR

Any Difference Between (int) 1 and 1 in PHP?

I was reading some code that a consultant provided us. It's a bit convoluted, and at the end of a function, it reads:
return (int) 1;
Instead of:
return 1;
PHP has a lot of magic in it; is this as bone-headed as it looks, or is there a valid reason to cast an integer as an integer?
No, it's the same. 1 is an integer literal.
See here these are all integer literals; casting to int has no effect:
$a = 1234; // decimal number
$a = -123; // a negative number
$a = 0123; // octal number (equivalent to 83 decimal)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
If you did return "1"; that would be an entirely different matter. There are some differences in behaviour between "1" (string) and 1 (int), namely with bitwise operators.
It's pretty bone headed. Integer literals are, well... integers.
1 === 1 however 1 !== '1'
also, when necessary, (as in this case it definitely isn't) I would suggest not typecasting with (int) use intval() instead.

Categories