|
Bitwise OperatorsBitwise operators allow you to turn specific bits within an integer on or off. If both the left- and right-hand parameters are strings, the bitwise operator will operate on the characters' ASCII values. <?php Table 6.3. Bitwise Operators
Warning:
Don't right shift for more than 32 bits on 32 bits systems. Don't left shift in case it results to number longer than 32 bits. Code Examples / Notes » language.operators.bitwise27-apr-2006 08:31
[Editors note: This is not true. You will have to check every possible combination, for instance: $a = array(); $b = ""; $c = null; $d = 0; will print "not equal" but if you set $b = null and $c = "" it will print "equal"] For the sake of completeness I want to note that a check for equality doesn't have so long winded as in the (wrong) example below. Because of simple laws of logic you don't have to check every possible combination of the variables. The following code will be no surprise for most of you, but for some people it could be helpful. -Tim <?php $a = 42 ; $b = 42 ; $c = 1138 ; $d = 1701 ; echo $a==$b && $b==$c && $c==$d ? "equal" : "not equal" ; // echoes not equal $a = 42 ; $b = 42 ; $c = 42 ; $d = 42 ; echo $a==$b && $b==$c && $c==$d ? "equal" : "not equal" ; // echoes equal ?> rob
Well, every programmer already knows this but for anyone new to the fun here's some quick clean code to determine if a number is odd or even. function oddeven($x){ if($x & 1) return "odd"; else return "even"; } visual
To perform bitwise operations on floats, or anything for that matter, in the binary representation of your choice, simply use pack() on the data with the appropriate parameters, then you can operate on the resulting strings. in the end just unpack()
xert
To determine number of bits set to 1 use: <?php function bits($val) { $v = (int)$val; $c = 0; for ($c=0; $v; $c++) { $v &= $v - 1; } return $c; } ?> Code from: http://graphics.stanford.edu/~seander/bithacks.html dasch
The function below can be rewritten to this: <?php function setflag (&$var, $flag, $set = true) { $var = $set ? ($var | $flag) : ($var & ~$flag); } ?> rizal dot almashoor
The following function will perform a 32-bit left shift on a 64-bit machine: <?php function leftshift32($number, $steps) { $binary = decbin($number).str_repeat("0", $steps); $binary = str_pad($binary, 32, "0", STR_PAD_LEFT); $binary = substr($binary, strlen($binary) - 32); return $binary{0} == "1" ? -(pow(2, 31) - bindec(substr($binary, 1))) : bindec($binary); } ?> sgarner
The bitwise AND operator behaves oddly inside an IF statement when used with equal arguments. <?php echo 9 & 8; // outputs '8' (correct) echo 8 & 8; // outputs '8' (correct) if (9 & 8 == 8) echo 'true'; else echo 'false'; // outputs 'true' (correct) if (8 & 8 == 8) echo 'true'; else echo 'false'; // outputs 'false' (wrong!!) ?> The solution is to add parentheses: <?php if ((8 & 8) == 8) echo 'true'; else echo 'false'; // outputs 'true' (correct) ?> Tested on PHP 5.2.1 jbrand1
So here's an interesting little thing that I do with bitwise operators, could potentially be useful to others. I have a roles based system which shows, among other things, menu entries based on a users role. The menu entries are stored in a mysql database as are the users and the roles. My users table looks like this: +----------+--------+ | Username | RoleID | +----------+--------+ | admin | 1 | | suser | 2 | | user | 4 | +----------+--------+ My roles table looks like this: +-------------------------------+--------+ | RoleName | RoleID | +-------------------------------+--------+ | System Administrator | 1 | | Super User | 2 | | User | 4 | +-------------------------------+--------+ My menus table looks like this: +-------------------+---------------------+---------+ | Menu_Title | MenuFile | Roles | +-------------------+---------------------+---------+ | Data | Data.php | 7 | | All Data | All_Data.php | 3 | | Shutdown | Shutdown.php | 1 | +-------------------+---------------------+---------+ Now, when the user logs in I run a select to see if they are valid: SELECT * FROM Users WHERE Username = '<USER>' AND Password = '<PW>' If no rows were returned I print an error message and redraw the login screen, otherwise I set some session variables: <?php $row = mysql_fetch_assoc($recordset); $_SESSION['Username'] = $row['Username']; $_SESSION['RoleID'] = $row['RoleID']; ?> In my MainMenu.php I check that a valid user is logged in and if so I generate the menu: <?php if( isset($_SESSION['Username']) && isset($_SESSION['RoleID']) ) { generateMenuEntries($_SESSION['RoleID']); } ?> <?php /********************************************/ /** Generates the menu */ /*******************************************/ function generateMenuEntries( $roleID ) { $menuQuery = sprintf("SELECT * FROM menus WHERE (Roles & %d) = %d", $roleID, $roleID); $menuRecordset = mysql_query($menuQuery, $myConn); while( $menu = mysql_fetch_assoc( $menuRecordset )) { echo ' <tr>'; echo ' <td width="3%"> </td> '; echo ' <td width="97%"><a href="'; echo $menu['MenuFile']; echo '">'; echo $items['Menu_Title']; echo '</a></td>'; echo ' </tr>'; } } ?> So the important part of the query is the (Roles & $roleID) = $roleID, that does a bitwise AND function and since only one bit is set in our role the value returned will either be 0 or the $roleID. I know this isn't the most secure way to handle the user/session data but it's sufficient for my needs. I have to be careful when I add roles so that it's 2^whatever. I wish I knew how to change the auto_increment so that it was just a bit shift. I suppose I could use an auto-generated ID field and do a stored procedure that calculates the role as 2^ID. I'll have to look into it. Hope this helps someone. redduck666
since i have no idea how do we get: echo 12 ^ 9; // Outputs '5' i searched for another tutorial, and this is what i found http://www.litfuel.net/tutorials/bitwise.htm, hopefully someone will find this useful ;) icy
Say... you really want to have say... more than 31 bits available to you in your happy bitmask. And you don't want to use floats. So, one solution would to have an array of bitmasks, that are accessed through some kind of interface. Here is my solution for this: A class to store an array of integers being the bitmasks. It can hold up to 66571993087 bits, and frees up unused bitmasks when there are no bits being stored in them. <?php /* Infinite* bits and bit handling in general. *Not infinite, sorry. Perceivably, the only limit to the bitmask class in storing bits would be the maximum limit of the index number, on 32 bit integer systems 2^31 - 1, so 2^31 * 31 - 1 = 66571993087 bits, assuming floats are 64 bit or something. I'm sure that's enough enough bits for anything.. I hope :D. */ DEFINE('INTEGER_LENGTH',31); // Stupid signed bit. class bitmask { protected $bitmask = array(); public function set( $bit ) // Set some bit { $key = (int) ($bit / INTEGER_LENGTH); $bit = (int) fmod($bit,INTEGER_LENGTH); $this->bitmask[$key] |= 1 << $bit; } public function remove( $bit ) // Remove some bit { $key = (int) ($bit / INTEGER_LENGTH); $bit = (int) fmod($bit,INTEGER_LENGTH); $this->bitmask[$key] &= ~ (1 << $bit); if(!$this->bitmask[$key]) unset($this->bitmask[$key]); } public function toggle( $bit ) // Toggle some bit { $key = (int) ($bit / INTEGER_LENGTH); $bit = (int) fmod($bit,INTEGER_LENGTH); $this->bitmask[$key] ^= 1 << $bit; if(!$this->bitmask[$key]) unset($this->bitmask[$key]); } public function read( $bit ) // Read some bit { $key = (int) ($bit / INTEGER_LENGTH); $bit = (int) fmod($bit,INTEGER_LENGTH); return $this->bitmask[$key] & (1 << $bit); } public function stringin($string) // Read a string of bits that can be up to the maximum amount of bits long. { $this->bitmask = array(); $array = str_split( strrev($string), INTEGER_LENGTH ); foreach( $array as $key => $value ) { if($value = bindec(strrev($value))) $this->bitmask[$key] = $value; } } public function stringout() // Print out a string of your nice little bits { $string = ""; $keys = array_keys($this->bitmask); sort($keys, SORT_NUMERIC); for($i = array_pop($keys);$i >= 0;$i--) { if($this->bitmask[$i]) $string .= sprintf("%0" . INTEGER_LENGTH . "b",$this->bitmask[$i]); } return $string; } public function clear() // Purge! { $this->bitmask = array(); } public function debug() // See what's going on in your bitmask array { var_dump($this->bitmask); } } ?> It treats a positive integer input as a bit, so you don't have to deal with the powers of 2 yourself. <?php $bitmask = new bitmask(); $bitmask->set(8979879); // Whatever $bitmask->set(888); if($bitmask->read(888)) print 'Happy!\n'; $bitmask->toggle(39393); // Yadda yadda $bitmask->remove(888); $bitmask->debug(); $bitmask->stringin("100101000101001000101010010101010 00000001000001"); print $bitmask->stringout() . "\n"; $bitmask->debug(); $bitmask->clear(); $bitmask->debug(); ?> Would produce: Happy! array(2) { [289673]=> int(65536) [1270]=> int(8388608) } 0000000000000001001010001010010001010100101010100 0000001000001 array(2) { [0]=> int(355106881) [1]=> int(37970) } array(0) { } alexrussell101
re the 12 ^ 9 = 5 comment, the link doesn't seem to work but here's the explanation (although if you're dealing with bitwise operators you really should get this): 12 in binary is 1100 9 in binary is 1001 If you XOR (the ^ operator) these two binary values you get the binary value 0101 (101) which is 5 in decimal. It's that simple. crizza
Personally I get a great deal of pleasure using bitwise operators for dealing with flags here is an example using c code because im a php noob, but the principal of bitwise ops is the same. #define F_WITH_DEBUG 0x01 #define F_WITH_HELP_INFO 0x02 #define F_BE_VERBOSE 0x04 unsigned short flags = 0; flags |= ( F_WITH_DEBUG | F_WITH_HELP_INFO | F_BE_VERBOSE ); /* now the first byte of flags look like this 00000111 */ /* check the status of flags */ if( flags & F_WITH_DEBUG) { /* do something */ } flags are great, I love *them. eric swanson
Perl vs. PHP implementation of the ^ operator: After attempting to translate a Perl module into PHP, I realized that Perl's implementation of the ^ operator is different than the PHP implementation. By default, Perl treats the variables as floats and PHP as integers. I was able to verify the PHP use of the operator by stating "use integer;" within the Perl module, which output the exact same result as PHP was using. The logical decision would be to cast every variable as (float) when using the ^ operator in PHP. However, this will not yield the same results. After about a half hour of banging my head against the wall, I discovered a gem and wrote a function using the binary-decimal conversions in PHP. /* not having much experience with bitwise operations, I cannot tell you that this is the BEST solution, but it certainly is a solution that finally works and always returns the EXACT same result Perl provides. */ function binxor($a, $b) { return bindec(decbin((float)$a ^ (float)$b)); } //normal PHP code will not yeild the same result as Perl $result = 3851235679 ^ 43814; //= -443704711 //to get the same result as Perl $result = binxor(3851235679, 43814); //= 3851262585 //YIPPEE!!! //to see the differences, try the following $a = 3851235679 XOR 43814; $b = 3851235679 ^ 43814; //integer result $c = (float)3851235679 ^ (float)43814; //same as $b $d = binxor(3851235679, 43814); //same as Perl!! echo("A: $a<br />"); echo("B: $b<br />"); echo("C: $c<br />"); echo("D: $d<br />"); louis /at/ mulliemedia.com
Note that the ^ operator, unlike in some other languages, is *not* the same as the pow() function.
tbrendstrup
note that the shift operators are arithmetic, not logic like in C. You may get unexpected results with negative numbers, see http://en.wikipedia.org/wiki/Bitwise_operation here's a function to do logic right shifts. <?php function lshiftright($var,$amt) { $mask = 0x40000000; if($var < 0) { $var &= 0x7FFFFFFF; $mask = $mask >> ($amt-1); return ($var >> $amt) | $mask; } return $var >> $amt; } $val = -10; printf("arithmetic shift on a negative integer %1\$032b %2\$032b %1\$0d %2\$0d ",$val, $val >> 1 ); printf("logic shift on a negative integer %1\$032b %2\$032b %1\$0d %2\$0d ",$val, lshiftright($val, 1)); printf("logic shift on a positive integer %1\$032b %2\$032b %1\$0d %2\$0d ",-$val, lshiftright(-$val, 1)); ?> gives the output: arithmetic shift on a negative integer 11111111111111111111111111110110 11111111111111111111111111111011 -10 -5 logic shift on a negative integer 11111111111111111111111111110110 01111111111111111111111111111011 -10 2147483643 logic shift on a positive integer 00000000000000000000000000001010 00000000000000000000000000000101 10 5 tanstep
Note that precedence is wrong for bitwise and comparison operators: use this: if((pow(2, $pos) & $_bits) > 0) NOT this: if(pow(2, $pos) & $_bits > 0) planev ea2005#planev.com
My very simple bit functions: setbit($bits,$bit) getbit($bits,$bit) unsetbit($bits,$bit) function setbit($bits,$i){ if (($i <= strlen($bits)-1) && ($i >= 0)) { $bits[strlen($bits)-1-$i] = "1"; } return $bits; } function unsetbit($bits,$i){ if (($i <= strlen($bits)-1) && ($i >= 0)) { $bits[strlen($bits)-1-$i] = "0"; } return $bits; } function getbit($bits,$i){ if (($i <= strlen($bits)-1) && ($i >= 0)) { $bit = $bits[strlen($bits)-1-$i]; } return $bit; } zewt
if you use bitwise you MUST make sure your variables are integers, otherwise you can get incorrect results. I recommend ALWAYS (int)$var & (int)$var2 This will save you many headaches when troubleshooting a completely illogical result. junk
I wanted to print a binary representation of an integer here it is <?php function binString($var, $safety = 0) { return ($var & 1) . ($var != 0 && $safety < 31 ? binString($var >> 1, $safety+1) : ""); } print binString(5); // would print 101 print binString(15); // would print 1111 ?> Explanation: the first expression after the return statement will evaluate to 1 or 0 according to the least significant bit. then we have our stop condition if there is still non zero bits left or if we are at the 32nd bit otherwise we call recursively on to the n-1 bits (by shifting out the least significant bit). zlel grxnslxves13
I refer to Eric Swanson's post on Perl VS PHP's implementation of xor. Actually, this is not an issue with the implementation of XOR, but a lot more to do with the lose-typing policy that PHP adopts. Freely switching between int and float is good for most cases, but problems happen when your value is near the word size of your machine. Which is to say, 32-bit machines will encounter problems with values that hover around 0x80000000 - primarily because PHP does not support unsigned integers. using bindec/decbin would address this issue as a work-around to do unsigned-int xor, but here's the real picture (i'm not claiming that this code will perform better, but this would be a better pedagogical code): <?php function unsigned_xor32 ($a, $b) { $a1 = $a & 0x7FFF0000; $a2 = $a & 0x0000FFFF; $a3 = $a & 0x80000000; $b1 = $b & 0x7FFF0000; $b2 = $b & 0x0000FFFF; $b3 = $b & 0x80000000; $c = ($a3 != $b3) ? 0x80000000 : 0; return (($a1 ^ $b1) |($a2 ^ $b2)) + $c; } $x = 3851235679; $y = 43814; echo " This is the value we want"; echo " 3851262585"; echo " The result of a native xor operation on integer values is treated as a signed integer"; echo " ".($x ^ $y); echo " We therefore perform the MSB separately"; echo " ".unsigned_xor32($x, $y); ?> This is really foundation stuff, but for those of you who missed this in college, there seems to be something on 2's complement here: http://www.evergreen.edu/biophysics/technotes/program/2s_comp.htm kendsnyder
I needed to perform a bitwise AND on floats and came up with this. There is probably a better way to do this with bit rotation, but this works. /** * Perform a float-safe bitwise AND comparison * * @param int/float $number The number to which to perform a bitwise AND * @param int/float $comparison The number with which to perform a bitwise AND * @return bool */ function safeBitCheck($number,$comparison) { if( $number < 2147483647 ) { return ($number & $comparison)==$comparison; } else { $binNumber = strrev(base_convert($number,10,2)); $binComparison = strrev(base_convert($comparison,10,2)); for( $i=0; $i<strlen($binComparison); $i++ ) { if( strlen($binNumber)<$i || ($binComparison{$i}==="1" && $binNumber{$i}==="0") ) { return false; } } return true; } } safeBitCheck(17,16); // true safeBitCheck(17,2); // false safeBitCheck((4294967296+8589934592),4294967296); // true safeBitCheck(2,8589934592); // false bryanagee
I found the 31-bit limitation on the bitwise ands to be a bit frustrating in large scale permission control applications. I have a situation involving page-level access with more than 50 pages. I was able to workaround the limitation by adding a loop that dropped 31 bits off of the right until the resource identifier bit is within the first 31. <?php $userlevel = $session->userlevel - 0; # the subtraction ensures int type $pg_code = pow(2,($pg_id-1)); while ($pg_code >= 2147483648) { $pg_code = $pg_code/pow(2,31); $userlevel = $session->userlevel/pow(2,31) ; } if (!($userlevel - 0 & $pg_code)) { #if not authorized, show the unauthorized page header('Location: Unauthorized.php'); exit; } ?> krang
Hopefully this may help someone understand the fun of Bitwise Operators.... The purpose of this function is to return a value from the GPC (Get, Post and Cookie) and do some basic formatting to it depending on the $VALIDATION value: <?PHP function RETURN_SUBMITTED_VALUE ($VARIABLE, $METHOD, $VALIDATION) { //------------------------------- // Get the value from the // relevant submit method... if ($METHOD == 'POST') { if (!isset($_POST[$VARIABLE])) $_POST[$VARIABLE] = ''; $VALUE = $_POST[$VARIABLE]; } elseif ($METHOD == 'COOKIE') { if (!isset($_COOKIE[$VARIABLE])) $_COOKIE[$VARIABLE] = ''; $VALUE = $_COOKIE[$VARIABLE]; } else { if (!isset($_GET[$VARIABLE])) $_GET[$VARIABLE] = ''; $VALUE = $_GET[$VARIABLE]; } //------------------------------- // If necessary strip the slashes. // the "GPC" means - GET, POST // COOKIE. if (ini_get ('magic_quotes_gpc') == true) { $VALUE = stripslashes($VALUE); } //------------------------------- // Now for the different types // of VALIDATION's if (($VALIDATION & 8) == 8) { $VALUE = (int)$VALUE; } if (($VALIDATION & 4) == 4) { $VALUE = strtolower($VALUE); } if (($VALIDATION & 2) == 2) { $VALUE = strip_tags($VALUE); } if (($VALIDATION & 1) == 1) { $VALUE = trim($VALUE); } //------------------------------- // Finally return the value return $VALUE; } echo RETURN_SUBMITTED_VALUE ('ID', 'GET', 8) . '<br />'; // Convert to an Integer echo RETURN_SUBMITTED_VALUE ('NAME', 'GET', 3) . '<br />'; // Trim Whitespace and Strip HTML tags echo RETURN_SUBMITTED_VALUE ('GENDER', 'GET', 6) . '<br />'; // Strip HTML tags and convert to lower case //----------------------------------------------- // If this script was loaded under the URL // index.php?ID=19a&NAME=Krang&GENDER=MalE // it would print // // 19 // Krang // male //----------------------------------------------- ?> For those that dont understand binary, the numbers you see are not random, they double each time (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024...) which allows you to mix and match the different function, eg... 1 + 2 = 3 (Trim Whitespace + Strip HTML) 2 + 4 = 6 (Strip HTML + Convert to lower case) zlel
Here're my 32-bit carry-discarding operations for those of you porting encryption algorithms from C. Be warned that some of these are not very efficient compared to the native operations, especially when called by heavy-duty encryption algorithms - but not discarding the carry bit may not land you the same results you get in C, simply because PHP's bitwise operations were not designed to work on fixed-sized registers. (If your ported encryption algo still doen't give you the same results, remember to check your Endian-ness!) function _BF_SHR32 ($x, $bits) { if ($bits==0) return $x; if ($bits==32) return 0; $y = ($x & 0x7FFFFFFF) >> $bits; if (0x80000000 & $x) { $y |= (1<<(31-$bits)); } return $y; } function _BF_SHL32 ($x, $bits) { if ($bits==0) return $x; if ($bits==32) return 0; $mask = (1<<(32-$bits)) - 1; return (($x & $mask) << $bits) & 0xFFFFFFFF; } function _BF_GETBYTE ($x, $y) { return _BF_SHR32 ($x, 8 * $y) & 0xFF; } function _BF_OR32 ($x, $y) { return ($x | $y) & 0xFFFFFFFF; } function _BF_ADD32 ($x, $y) { $x = $x & 0xFFFFFFFF; $y = $y & 0xFFFFFFFF; $total = 0; $carry = 0; for ($i=0; $i<4; $i++) { $byte_x = _BF_GETBYTE($x, $i); $byte_y = _BF_GETBYTE($y, $i); $sum = $byte_x + $byte_y; $result = $sum & 0xFF; $carryforward = _BF_SHR32($sum, 8); $sum = $result + $carry; $result = $sum & 0xFF; $carry = $carryforward + _BF_SHR32($sum, 8); $total = _BF_OR32(_BF_SHL32($result, $i*8), $total); } return $total; } andrew
Here is a useful function for setting flags (or bits). It takes three paramaters: 1. $var This is the variable whose flag you want to set 2. $flag This is the flag(s) you want set 3. $set This is either ON or OFF Simply adding or subtracting a flag is not a good idea. For example, if the variable is in binary 0101 (thats 5 in dec) and you want to turn the 1 bit off subtracttion would work. 5-1=4 which would be 0100. However, the variable is 0100, and you want subtracted, 4-1 =3 or 0011. What you intended to do was to turn off the one bit regardless of whether it is on or off. This function will turn on or off a bit(or bits) regardless of the bit's current state. <?php define('ON', 1); define('OFF', 0); function setflag(&$var, $flag, $set=ON ) { if (($set == ON)) $var = ($var | $flag); if (($set == OFF)) $var = ($var & ~$flag); return; } ?> For a full test of this try this code: <pre> <?php define ('f1', 1); define ('f2', 2); define ('f4', 4); define ('f8', 8); define('ON', 1); define('OFF', 0); function setflag(&$var, $flag, $set=ON ) { if (($set == ON)) $var = ($var | $flag); if (($set == OFF)) $var = ($var & ~$flag); return; } function dbi($var){ // display number as binary (four bits) $output = ($var & f8) ? '1' : '0'; $output .= ($var & f4) ? '1' : '0'; $output .= ($var & f2) ? '1' : '0'; $output .= ($var & f1) ? '1' : '0'; return $output; } $var1 = ( f8 | f2 | f1 ); echo (" " . dbi($var1). "\n" ); echo ("ON " . dbi(f4). "\n" ); setflag($var1, f4, ON); echo ("IS " . dbi($var1). "\n" ); echo ("\n"); $var2 = ( f8 | f2 | f1 ); echo (" " . dbi($var2). "\n" ); echo ("OFF " . dbi(f1). "\n" ); setflag($var2, f1, OFF); echo ("IS " . dbi($var2). "\n" ); echo ("\n"); echo ("\n"); $var3 = ( f8 | f2 | f1 ); echo (" " . dbi($var3). "\n" ); echo ("ON " . dbi((f4 | f1)). "\n" ); setflag($var3, (f4 | f1), ON); echo ("IS " . dbi($var3). "\n" ); echo ("\n"); $var4 = ( f8 | f2 | f1 ); echo (" " . dbi($var4). "\n" ); echo ("OFF " . dbi((f4 | f1)). "\n" ); setflag($var4, (f4 | f1), OFF); echo ("IS " . dbi($var4). "\n" ); echo ("\n"); ?> </pre> Which returns: 1011 ON 0100 IS 1111 1011 OFF 0001 IS 1010 1011 ON 0101 IS 1111 0100 OFF 0101 IS 0000 gcg
function xnor($a, $b) { return ~($a ^ $b); } XNOR is very usefull ;D nina cording
For those who were searching for a way to actually rotate the bits of a number, here are some little functions I wrote: <?php function bitRotate32($value,$amount) { if ($amount>0) { $amount %= 32; $value = ($value<<$amount) | ($value>>(32-$amount)); } elseif ($amount<0) { $amount = -$amount%32; $value = ($value>>$amount) | ($value<<(32-$amount)); } return $value; } function bitRotate($value,$amount,$bits) { $mask = ($bits<32) ? 0x7fffffff >> (31-$bits) : 0xffffffff; if ($amount>0) { $amount %= $bits; $value = ($value<<$amount) | ($value>>($bits-$amount)); } elseif ($amount<0) { $amount = -$amount%$bits; $value = ($value>>$amount) | ($value<<($bits-$amount)); } return $value & $mask; } // test the rotation: $test = 4123; for ($i=0; $i<64; $i++) { $value = bitRotate($test,-$i,8); // rotates 8 bits to the left (-$amount) echo sprintf("%032b<br/>",$value); } ?> richard-slater.co.uk
For those (like me) who are trying to do bit masking with very large numbers, here is a useful function to do the work for you. <?php function isBitSet($bitMask, $bitMap) { return (bool) gmp_intval(gmp_div(gmp_and($bitMask, $bitMap),$bitMask)); } ?> achim
For all of you who are new to bitwise operatons (like me)... There is a great article on gamedev.net explaining the basics of this: "Bitwise Operations in C" by Joseph "Ironblayde" Farrell http://www.gamedev.net/reference/articles/article1563.asp gemini_5
Extending the comment by andrew at thepenry dot net: His (slightly altered) function for reference: <?php function setflag(&$var, $flag, $set) { if (($set == 1)) $var = ($var | $flag); if (($set == 0)) $var = ($var & ~$flag); return; } ?> You could shorten the operations to: <?php $var |= $flag; // for setting $var &= ~$flag; // for unsetting ?> Which kind of eliminates the need for a function. don dot hosek
Don't forget operator precedence. == has a higher precedence than does & so in the cases that you've written if (9 & 8 == 8) echo 'true'; else echo 'false'; is the same as 9 & (8 ==8) which is 9 & true or 9 & 1 which is 1 which is true if (8 & 8 == 8) echo 'true'; else echo 'false'; is the same as 8 & (8 == 8) which is 8 & true or 8 & 1 which is 0 which is false Putting in parentheses is required to cause the bitwise and to take place before the comparison. john l
Bitwise operators are swell, but (a & b & c & d) == a is not a way to test for four-way equality. If a is zero, it'll always be true, and in general it will be true any time a has no bits not also in the other three values. tanstep
Beware that strings can be ANDed, XORed, and ORed just fine. When printing the results of a bitwise operation, results can be a bit confusing, since operands may be converted to strings BEFORE bitwise operator execution. so, use this: print('result: '); print(pow(2, $pos) & $this->_bits); print(' '); NOT this print("result: " . pow(2, $pos) & $this->_bits . " "); séb.
Another practical case... <?php header('Content-Type: text/plain') ; // We want to know the power-2 based numbers of $x $x = 9124 ; $n = 1 ; while ( $x > 0 ) { if ( $x & 1 == 1 ) { echo $n, "\n" ; } $n *= 2 ; $x >>= 1 ; } // Will output... // 4 // 32 // 128 // 256 // 512 // 8192 ?> temp dot 2004-03-27
Always use type casting! <?php echo (134 & 512) . "\n"; echo ("134" & "512") . "\n"; echo ((int)"134" & (int)"512") . "\n"; ?> Output: 0 110 (wrong!) 0 joel
All shifts are signed shifts. The shift is performed with the shift count modulo 32, which explains the behavior which looks like a bit rotation, mentioned above. Example: $bit = 0x20000000; print "$bit << 5 == " . ($bit << 5) . $prod . "<br />"; print "$bit >> 5 == " . ($bit >> 5) . $prod . "<br />"; print "$bit >> 37 == " . ($bit >> 37) . $prod . "<br />"; $bit = 4; print "$bit >> 5 == " . ($bit >> 5) . $prod . "<br />"; print "$bit << 5 == " . ($bit << 5) . $prod . "<br />"; print "$bit << 37 == " . ($bit << 37) . $prod . "<br />"; Results: 536870912 << 5 == 0 536870912 >> 5 == 16777216 536870912 >> 37 == 16777216 4 >> 5 == 0 4 << 5 == 128 4 << 37 == 128 lars dot jensen
A useful set of functions, making it easier to play with bits as a set of booleans. $bit is a integer between 1 and 32 representing the position of the bit you wish to manipulate. <?php function setbit($val, $bit) { if (readbit($val, $bit)) return $val; return $val += '0x'.dechex(1<<($bit-1)); } function clearbit($val, $bit) { if (!readbit($val, $bit)) return $val; return $val^(0+('0x'.dechex(1<<($bit-1)))); } function readbit($val, $bit) { return ($val&(0+('0x'.dechex(1<<($bit-1)))))?'1':'0'; } function debug($var, $bitlength=32) { for ($j=$bitlength;$j>0;$j--) { echo readbit($var, $j); if ($j%4 == 1) echo ' '; } } ?> séb.
A bitwise operators practical case : <?php // We want to know the red, green and blue values of this color : $color = 0xFEA946 ; $red = $color >> 16 ; $green = ($color & 0x00FF00) >> 8 ; $blue = $color & 0x0000FF ; printf('Red : %X (%d), Green : %X (%d), Blue : %X (%d)', $red, $red, $green, $green, $blue, $blue) ; // Will display... // Red : FE (254), Green : A9 (169), Blue : 46 (70) ?> rdewaard
@jbrand1 at uwe_emm_bee_see dot edu: "I have to be careful when I add roles so that it's 2^whatever. I wish I knew how to change the auto_increment so that it was just a bit shift." If you store your roles in MySQL you might consider NOT using a table 'roles' but adding a field 'roles' to the table 'user' using the datatype SET for that field. The name for each role will have a decimal value 2^whatever! See http://www.vbmysql.com/articles/mysqlsetdatatype.html for details and ideas. keuleu
<?php function xor_swap(&$a, &$b) { if($a==$b) { return; } $c = $a ^ $b; $b = $c ^ $b; $a = $c ^ $a; } ?> Explanation: $c=$a*^$b*; $b=$c^$b*; => $b=($a*^$b*)^$b*; => $b=$a*^0; => $b=$a*; $a=$c^$a*; => $a=($a*^$b*)^$a; => $a=$b*^0; =>$a=$b*; *original value of the variable Now a version of xor_swap() with no buffer ($c): <?php function xor_swap(&$a,&$b){ if($a==$b) { return; } $a=$a^$b; $b=$a^$b; $a=$a^$b; } ?> Explanation: $a=$a*^$b*; $b=$a^$b*; => $b=($a*^$b*)^$b*; => $b=$a*; $a=$a^$b; => $a=($a*^$b*)^$a*; =>$a=$b*; * original value of the variable ~
<?php function xor_swap(&$a, &$b) { if($a==$b) { return; } $c = $a ^ $b; $b = $c ^ $b; $a = $c ^ $a; } function swap (&$a, &$b) { $buffer = $a; $a = $b; $b = $buffer; } $a = 1; $b = 2; echo '$a is '.$a.'<br />$b is '.$b.'<hr />'; swap($a, $b); echo '$a is '.$a.'<br />$b is '.$b.'<hr />'; xor_swap($a, $b); echo '$a is '.$a.'<br />$b is '.$b; ?> Output: $a is 1 $b is 2 -------------- $a is 2 $b is 1 -------------- $a is 1 $b is 2 xavier daull
<?php // Extract part of a binary data - due to windows system limitations (and this code), bit extracted length($firstbit to $lastbit included) is limited to 31 bits function sub_bindata($mybindata, $firstbit = 7, $lastbit = 0, $highestbitfirst = true) { // 1. Create a bit mask of the right size by triming left and right // 2. select bits by an AND on $mybindata // 3. shift right to get only length needed if($highestbitfirst) return (((0x7FFFFFFF >> (30+$lastbit-$firstbit))<<($lastbit)) & $mybindata) >> ($lastbit); else return (((0x7FFFFFFF >> (30-$lastbit+$firstbit))<<(30-$lastbit)) & $mybindata) >> (30-$lastbit); } ?> |