p2p.wrox.com Forums

Need to download code?

View our list of code downloads.


  Return to Index  

beginning_php thread: Explain the Shift thing to me? ( << and >> )


Message #1 by "Dan Ostrowski" <dan@t...> on Mon, 20 May 2002 14:05:43
I am not sure how to wrap my brain around it.  Does it have something to 
do with the number of bits in an argument?  I am not even sure i get THAT.

I have read the documentation on it, but it doesn't make too much sense to 
me. PLUS there is this code i am reading over right now...

<?php

// define helper constants

define('LOCAL'        1 << 0);
define('REMOTE'       1 << 1);
define('TO_LOCAL',    LOCAL);
define('TO_REMOTE',   REMOTE);
define('FROM_LOCAL',  LOCAL << 2);
define('FROM_REMOTE', REMOTE << 2);

//go on to do FTP class coding 

?>

this is from the ProPHP4 book.  Why are they using these operators? 

Thanks for any help,

regards,

dan
Message #2 by "Nikolai Devereaux" <yomama@u...> on Mon, 20 May 2002 10:22:41 -0700
Shift operators shift bits to the left or right.  They essentially perform
multiplications or divisions by powers of two, but they do it in one
operation instead of several.

Let's take a number, 42, which is 00101010 in binary.

Shift that to the left two bits (42 << 2) we get 10101000.  Get it?  Now
what did we really do here?  If we convert that number to decimal we get
168.

168 = 42 * 4.  or more appropriately,
168 = 42 * (2^2)
              +--->  (The number of positions shifted)

each time we shift a bit to the left, we multiply by two.  Each time we
shift to the right, we divide by two.

(42 >> 1) = 00010101.  Convert to decimal, and you get 21 as expected.


Now, on to the PHP side of things:

> define('LOCAL'        1 << 0);
> define('REMOTE'       1 << 1);
> define('TO_LOCAL',    LOCAL);
> define('TO_REMOTE',   REMOTE);
> define('FROM_LOCAL',  LOCAL << 2);
> define('FROM_REMOTE', REMOTE << 2);

This is just the author's way of defining unique named constants.  When all
is said and done, you'll end up with this:

VAR          DECIMAL   BINARY
LOCAL           1         0001
REMOTE          2         0010
TO_LOCAL        1         0001
TO_REMOTE       2         0010
FROM_LOCAL      4         0100
FROM REMOTE     8         1000


From the context, the only four values that make sense are the TO_xx and
FROM_xx values.  Notice that they are not only unique, but each has only one
bit set in their binary representation.  This is a common practice in
setting up bitmasks -- where each bit set in a number represents something.

The most common bitmask you'll see is a 9-bit mask used in unix permissions.

rwxrwxrwx is the "ls -l" representation of the binary number 111111111
(decimal 511).

Each number between 0 and 511 (inclusive) specifies a different permission
range for the user, group, and world for a file or directory.

Let's go back to 42 (00101010).  Let's add a leading 0 to make it a nine bit
representation (This is fine -- decimal 0000004 is still 4)

000101010
---r-x-w-

That file (oddly enough, i know) has no permissions set for the owner, read
and execute permissions for the group, and write permissions for the world.
(Sounds like my public_html dir... =\)

Hope this helps,

Nik







Message #3 by "Dan Ostrowski" <dan@t...> on Mon, 20 May 2002 21:45:17
As always, thanks a lot Nik!

I was reading over the documentation online and THIS was really the thing 
that was stumping me:

-----------------------------------------
Bit shifting (at least in PHP4) seems to preserve the sign, except that a 1
shifted to the sign bit makes a positive number negative. Examples:
echo ( 1 << 2 ); // Returns 4
echo ( -1 << 2 ); // Returns -4
echo ( -3 >> 1 ); // Returns -2
echo ( 1 << 31 ); // Returns -2147483648
echo ( (1<<31) >> 31 ); // Returns -1 [negative sign bit
preserved on right shift].
echo (-1 >> 100); // Returns -1 [-1>>X = -1 for all X].
-----------------------------------------


this was the one that was making me unsure about most of it:

echo ( 1 << 31 ); // Returns -2147483648

how does this get turned negative?

anyhow it makes a lot more sense now, thank you very much!

Dan
Message #4 by "Nikolai Devereaux" <yomama@u...> on Mon, 20 May 2002 14:58:34 -0700
Okay -- positive and negative numbers are not represented the same way with
just a sign bit differentiating them.  They're stored in two's complement
notation.

<aside>
Are you familiar with this?  If not, the gist of it is that to go from
negative to positive (or vice versa), flip all the bits and add 1.

 4 = 0000 0100

-4 = 1111 1011 (flip bits)
   + 0000 0001 (add one)
   -----------
     1111 1100 (result)
</aside>

Anyway, the PHP interpreter seems to use logical right-shifting, which means
that if the highest bit is 1 and you shift right, it shifts in a 1 to
preserve sign.  If it's 0, shift in 0.

I'll show you the (16-bit) before/after of these shifts to make more sense.

BEFORE                          AFTER

> echo ( 1 << 2 ); // Returns 4
00000000 00000001               00000000 00000100


> echo ( -1 << 2 ); // Returns -4
11111111 11111111               11111111 11111100


> echo ( -3 >> 1 ); // Returns -2
11111111 11111101               11111111 11111110


> echo ( 1 << 15 ); // Returns -32768
(pretend it's being shifter 15 instead of 31)
00000000 00000001               10000000 00000000


> echo ( (1<<15) >> 15 ); // Returns -1 [negative sign bit
> preserved on right shift].
the first part returns 100...0
shifting back 15 bits returns   11111111 11111111



hth,

nik

Message #5 by "Dan Ostrowski" <dan@t...> on Mon, 20 May 2002 23:45:40
it does.  very much.

i think i need to look into bitwise stuff a bit more... i hate being a 
n00b on this kind of stuff... =)

thanks again, as always, Nik.

regards,
dan
Message #6 by "Nikolai Devereaux" <yomama@u...> on Mon, 20 May 2002 17:36:29 -0700
As always, It's my pleasure.

take care,

nik


  Return to Index