BITWISE OPERATORS and PHP CLASSES
As a webmaster myself, I've found that breaking down large apps into CLASSES make tough jobs even easier. For example, on one of the websites I maintain, I have a large group of Artists who wish to sell their artwork on the internet. They wanted the website to act like a real Gallery where artwork can be displayed, but not for sale, etc., etc. My severly truncated Artwork class below shows how I use Bitwise Operators to control a single integer called flags.
<?php
class Artwork
{
protected static $HIDDEN = 1; // bitmask for 1st bit (0x1) - do not show this item
protected static $NFS = 2; // bitmask for 2nd bit (0x2) - not for sale
protected static $SOLD = 4; // bitmask for 3rd bit (0x4) - item is already sold
protected $flags = 0; // the property we're interested in...
public function isHidden(){
return ($this->flags & self::$HIDDEN > 0);
}
public function isNotForSale(){
return ($this->flags & self::$NFS > 0);
}
public function isSold(){
return ($this->flags & self::$SOLD > 0);
}
public function setHidden($hide){
$this->flags = ($doNotSell ? ($this->flags | self::$HIDDEN) : ($this->flags & ~self::$HIDDEN));
}
public function setNotForSale($doNotSell){
$this->flags = ($hide ? ($this->flags | self::$NFS) : ($this->flags & ~self::$NFS));
}
public function setSold($sold){
$this->flags = ($sold ? ($this->flags | self::$SOLD) : ($this->flags & ~self::$SOLD));
}
public function __toString(){
return "Artwork [flags=$this->flags]";
}
}
$art = new Artwork();
$art->setSold(true);
echo $art; // outputs: Artwork [flags=4]
?>
With the code example above, $art->flags = 4, indicating that this artwork is still showing on the website, but visitors cannot purchase it because it has been sold already (and the Add to Cart link dissappears). If the artwork is hidden, then no one would be able to see it at all, and if it is marked Not For Sale, then it cannot be purchased and an icon will be shown to indicate that. You can see that a simple flags property can pull more than its fair share of duties.
Bit-Operatoren
Bit-Operatoren erlauben es, in einem Integer bestimmte Bits "ein- oder auszuschalten" (auf 0 oder 1 zu setzen). Wenn beide, der links- und rechtsseitige Parameter, Zeichenketten sind, arbeiten die Bit-Operatoren mit ASCII-Werten der einzelnen Zeichen.
<?php
echo 12 ^ 9; // Ausgabe '5'
echo "12" ^ "9"; // Ausgabe: das Backspace-Zeichen (ascii 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello"; // Gibt die ASCII-Werte #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4 aus
?>
| Beispiel | Name | Ergebnis |
|---|---|---|
| $a & $b | Und | Bits, die in $a und $b gesetzt sind werden gesetzt. |
| $a | $b | Oder | Bits, die in $a oder $b gesetzt sind werden gesetzt. |
| $a ^ $b | Entweder oder (Xor) | Bits, die entweder in $a oder $b gesetzt sind, werden gesetzt aber nicht in beiden. |
| ~ $a | Nicht | Die Bits, die in $a nicht gesetzt sind, werden gesetzt und umgekehrt. |
| $a << $b | Nach links verschieben | Verschiebung der Bits von $a um $b Stellen nach links (jede Stelle entspricht einer Mulitplikation mit zwei). |
| $a >> $b | Nach rechts verschieben | Verschiebt die Bits von $a um $b Stellen nach rechts (jede Stelle entspricht einer Division durch zwei). |
Bit-Operatoren
wbcarts at juno dot com
27-Sep-2008 10:32
27-Sep-2008 10:32
lfarquaad+php at noSpam dot gmail dot com
28-Aug-2008 12:38
28-Aug-2008 12:38
@alexander dot dejong at home dot nl:
Your code for del_flag is incorrect, !($flag_check) just negates the value, probably resulting to 0. So it always returns 0…
The correct code is:
<?php
function del_flag($flags, $flag_check) {
return ($flags & ~$flag_check);
}
?>
razboinik at gadast dot net
25-Aug-2008 08:39
25-Aug-2008 08:39
i had a real bad time with bitwise operations
doesn't work well with unsinged 32 bits, this have reported elsewhere but it took me a while to find a work around so here it is, taken from
http://brian.moonspot.net/2007/10/23/integer-conversion-issue/
function num_trans($value)
{
if ($value < 0)
$value += 0x100000000;
return $value;
}
function bitand($a, $b)
{
return num_trans($a)&num_trans($b);
}
function bitor($a, $b)
{
return num_trans($a)|num_trans($b);
}
function bitxor($a, $b)
{
return num_trans($a)^num_trans($b);
}
alexander dot dejong at home dot nl
21-Aug-2008 12:53
21-Aug-2008 12:53
@darkelder at php dot net
You could better implement it different:
<?php
class flags {
function has_flag($flags, $flag_check) {
return ($flags & $flag_check) == $flag_check);
}
function add_flag($flags, $flag_check) {
return ($flags | $flag_check);
}
function del_flag($flags, $flag_check) {
return ($flags & !($flag_check);
}
}
?>
darkelder at php dot net
18-Aug-2008 12:49
18-Aug-2008 12:49
Here is a usefull class to work with flags:
<?php
class flags {
function has_flag($flags, $flag_check) {
if (($flags & $flag_check) == $flag_check) {
return true;
}
return false;
}
function add_flag($flags, $flag_check) {
// already have the flag, so return it as it is
if ($this->has_flag($flags, $flag_check)) {
return $flags;
}
return $flags ^ $flag_check;
}
function del_flag($flags, $flag_check) {
// already have not the flag, so return it as it is
if (!$this->has_flag($flags, $flag_check)) {
return $flags;
}
return $flags ^ $flag_check;
}
}
?>
Anonymous
18-Aug-2008 09:29
18-Aug-2008 09:29
@nikodrumer at gmail dot com
You could use XOR for cryptographic bases, but you should use the already implemented algorithms, if able.
Encrypting an sensitive text using XOR can be done, and is safe if the length of the string is as long as or shorter as the length of the key. In all other cases the text could be broken with a polyalfabethic frequency analyse. In a short text this is rather difficult. But when the text is rather large (for example, 20*length of your key), it's done quite easely. And an MD5 doesn't make it safer, in fact, it makes the length of the key fixed, so it even gets easier for a potential analist/attacker to break the text.
Therefor, there is no actuall reason to use this, 'cause there are plenty of other algorithms supplied, which are wáy safer.
m0sh at hotmail dot com
07-Aug-2008 09:03
07-Aug-2008 09:03
@greenone - nice function, thanks. I've adapted it for key usage:
<?php
function bitxor($str, $key) {
$xorWidth = PHP_INT_SIZE*8;
// split
$o1 = str_split($str, $xorWidth);
$o2 = str_split(str_pad('', strlen($str), $key), $xorWidth);
$res = '';
$runs = count($o1);
for($i=0;$i<$runs;$i++)
$res .= decbin(bindec($o1[$i]) ^ bindec($o2[$i]));
return $res;
}
?>
dale dot liszka at gmail dot com
09-Jul-2008 07:14
09-Jul-2008 07:14
Here is how to use multiple flags (for those who learn better by example, like me):
<?php
echo "|asdf".chr(9).chr(128)."_123|";
echo "\n";
// "bitwise conjunction" means logic OR / bitwise |
echo filter_var("|asdf".chr(9).chr(128)."_123\n|" ,FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
/*
Results:
|asdf �_123|
|asdf_123|
*/
?>
strata_ranger at hotmail dot com
08-Jul-2008 08:23
08-Jul-2008 08:23
Quick reminder about an easy gotcha: When using the ~ operator on variables make sure you know what the variable's type is -- typecast when unsure.
I learned this the hard way when using the ~ and & operators to test bits in an integer context, without realizing that one of my variables was actually initialized as a string:
<?php
$foo = 0; // $foo is int
$bar = '0'; // $bar is string
.
.
.
// This works
if (~$foo & 0x20)
{
...
}
// This doesn't work
if (~$bar & 0x20)
{
...
}
?>
The first case is straightforward; the second case is a little more underhanded:
- ($bar) is string, so the ~ operator will use its ASCII value, 0x30
- (~$bar) returns ASCII character 0xFFCF (on 32-bit systems)
- (0x20) is an integer, so the & operator will use integer values
- (~$bar) is not a number, so its integer value is zero
- (~$bar & 0x20) equals zero
In my case the variable was a class member initialized from an include()'d file, so it took a good while to hunt down....
greenone
02-Jul-2008 09:32
02-Jul-2008 09:32
here's a fast alternative to compute the xor-value of two bitstrings of an arbitrary (but same) length.
<?php
/**
* xor-op for bitstrings of arbitrary length
* bitstrings must have same length
*
* @param string $o1
* @param string $o2
* @return string
*/
function bitxor($o1, $o2) {
$xorWidth = PHP_INT_SIZE*8;
// split
$o1 = str_split($o1, $xorWidth);
$o2 = str_split($o2, $xorWidth);
$res = '';
$runs = count($o1);
for($i=0;$i<$runs;$i++)
$res .= decbin(bindec($o1[$i]) ^ bindec($o2[$i]));
return $res;
}
?>
bartbons at debster.nl
07-Apr-2008 11:27
07-Apr-2008 11:27
@kendsnyder at gmail dot com
Thanx for your great function. But your function is not 100% correct. It should be:
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) - 1 <$i || ($binComparison{$i}==="1" && $binNumber{$i}==="0") ) {
return false;
}
}
return true;
}
}
Mind the 'minus 1' on "if( strlen($binNumber) - 1 <$i".
cheers, Bart
nikodrumer at gmail dot com
24-Feb-2008 11:56
24-Feb-2008 11:56
Sorry for my english, I'm French.
We can create, a function to crypt/decrypt a string with a key :
The function :
<?php
function _xor($message, $key)
{
$keylen = strlen($key);
$messagelen = strlen($message);
for($i=0; $i<$messagelen; $i++)
$message[$i] = ~($message[$i]^$key[$i%$keylen]);
return $message;
}
?>
To crypt :
<?php
echo _xor('My string', 'key');
?>
To decrypt :
<?php
echo _xor('…âõ½¹¯£ý', 'key');
?>
For a better security, we can use sha1() and md5() :
<?php
echo _xor('My string', sha1(md5('key')));
?>
ironiridis at gmail dot com
26-Jan-2008 10:04
26-Jan-2008 10:04
There are some great notes here, but some of them are not as stellar as others. Take a look at the date they were posted and and replies to them before using them in anything but the most trivial cases.
For example, any function which uses implicit string to integer casting to evaluate hexadecimal.
This is bad code:
<?php
$integer_a = 41762;
$integer_b = (0+('0x'.dechex($integer_a << 1)));
?>
This is better [but still bad] code:
<?php
$integer_a = 41762;
$integer_b = intval(dechex($integer_a << 1), 16);
?>
This is probably optimal:
<?php
$integer_a = 41762;
$integer_b = (int)$integer_a << 1; // explicit cast
?>
Also, don't re-invent the wheel.
This function is unreadable, [needlessly] recursive, and superfluous:
<?php
function binString($var, $safety = 0) {
return ($var & 1) . ($var != 0 && $safety < 31 ? binString($var >> 1, $safety+1) : "");
}
print(binString(41762));
?>
This code does the same thing, and it's built-in:
<?php
printf('%b', 41792); // you'd do well to learn about printf()
?>
As always, if there are six ways to do it in C, there are 50 ways to do it in PHP. No method is wrong as long as it produces the correct result, but only a few methods will upgrade reliably, be portable, and be readable.
rvdh90 at NOSPAM dot hotmail dot com
16-Jan-2008 01:11
16-Jan-2008 01:11
<?php
function CheckFlag( $flagvalues, $flag )
{
$flag = intval( $flag );
$flagvalues = intval( $flagvalues );
return (($flagvalues & $flag) == $flag);
}
?>
Then define some constants with "binary" values, 1, 2, 4, 8 etc.. and you have your basic flag system!
forlamp at msn dot com
07-Dec-2007 03:35
07-Dec-2007 03:35
two's complement logical operation for 32-bit.
$x must be (int) when passing it to this function to work properly.
function comp2($x) // 32bit bitwise complement
{
$mask = 0x80000000;
if ($x < 0)
{
$x &= 0x7FFFFFFF;
$x = ~$x;
return $x ^ $mask;
}
else
{
$x = $x ^ 0x7FFFFFFF;
return $x | $mask;
}
}
Visual
20-Jun-2007 03:42
20-Jun-2007 03:42
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()
kendsnyder at gmail dot com
02-Jun-2007 12:30
02-Jun-2007 12:30
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
don dot hosek at gmail dot com
25-Apr-2007 03:05
25-Apr-2007 03:05
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.
sgarner at expio dot co dot nz
23-Apr-2007 07:04
23-Apr-2007 07:04
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
bryanagee at gmail dot com
08-Feb-2007 08:19
08-Feb-2007 08:19
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;
}
?>
zewt at hotmail dot com
12-Jan-2007 08:28
12-Jan-2007 08:28
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.
rizal dot almashoor at gmail dot com
14-Nov-2006 01:12
14-Nov-2006 01:12
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);
}
?>
keuleu at hotmail dot com
20-Sep-2006 12:10
20-Sep-2006 12:10
<?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
~
28-Aug-2006 12:49
28-Aug-2006 12:49
<?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
27-Apr-2006 09: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
?>
Xavier Daull
04-Feb-2006 10:34
04-Feb-2006 10:34
<?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);
}
?>
John L
02-Feb-2006 11:11
02-Feb-2006 11:11
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.
Nina Cording
29-Oct-2005 06:50
29-Oct-2005 06:50
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);
}
?>
zlel grxnslxves13 at hotmail dot com~=s/x/ee/g
27-Oct-2005 04:30
27-Oct-2005 04:30
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 "<br>This is the value we want";
echo "<br>3851262585";
echo "<br>The result of a native xor operation on integer values is treated as a signed integer";
echo "<br>".($x ^ $y);
echo "<br>We therefore perform the MSB separately";
echo "<br>".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
zlel
27-Oct-2005 02:22
27-Oct-2005 02:22
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;
}
Tbrendstrup
29-Sep-2005 02:23
29-Sep-2005 02:23
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<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",$val, $val >> 1 );
printf("logic shift on a negative integer<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",$val, lshiftright($val, 1));
printf("logic shift on a positive integer<br>%1\$032b<br>%2\$032b<br>%1\$0d<br>%2\$0d<br>",-$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
junk at spheresys dot com
22-Sep-2005 08:25
22-Sep-2005 08:25
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).
Planev ea2005#planev.com
02-Sep-2005 03:42
02-Sep-2005 03:42
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;
}
Eric Swanson
01-Sep-2005 02:19
01-Sep-2005 02:19
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 />");
alexrussell101 at gmail dot com
25-Jul-2005 01:28
25-Jul-2005 01:28
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.
redduck666 at gmail dot com
23-Jul-2005 12:26
23-Jul-2005 12:26
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 ;)
Séb.
19-Apr-2005 04:28
19-Apr-2005 04:28
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
?>
Séb.
05-Mar-2005 12:13
05-Mar-2005 12:13
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)
?>
icy at digitalitcc dot com
24-Feb-2005 08:24
24-Feb-2005 08:24
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) {
}
louis /at/ mulliemedia.com
20-Jan-2005 11:12
20-Jan-2005 11:12
Note that the ^ operator, unlike in some other languages, is *not* the same as the pow() function.
dasch at ulmail dot net
14-Dec-2004 09:06
14-Dec-2004 09:06
The function below can be rewritten to this:
<?php
function setflag (&$var, $flag, $set = true)
{
$var = $set ? ($var | $flag) : ($var & ~$flag);
}
?>
Gemini_5
08-Sep-2004 12:06
08-Sep-2004 12:06
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.
rdewaard at DONTSPAMME dot xs4all dot nl
14-Apr-2004 09:36
14-Apr-2004 09:36
@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.
xert
31-Mar-2004 03:11
31-Mar-2004 03:11
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
temp dot 2004-03-27 at fobit dot de
28-Mar-2004 09:58
28-Mar-2004 09:58
Always use type casting!
<?php
echo (134 & 512) . "\n";
echo ("134" & "512") . "\n";
echo ((int)"134" & (int)"512") . "\n";
?>
Output:
0
110 (wrong!)
0
lars dot jensen at ljweb dot com
26-Mar-2004 12:27
26-Mar-2004 12:27
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