sir p freakly has asked for the wisdom of the Perl Monks concerning the following question:
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: bitwise operators
by dvergin (Monsignor) on May 28, 2001 at 05:23 UTC | |
First, in order to make the answer to your question more clear, let's look at the question you did NOT ask. As the docs state, there is a difference between 123.45 & 234.56 and "123.45" & "234.56". In the first case, the two numbers will be truncated to integers and then the two values 123 and 234 will (in effect) be taken in their binary representation and ANDed. (Doing these in my head as I go -- I may slip a bit or two.) Thus:
So the result of evaluating 123.45 & 234.56 can be thought of as depending on the binary representation of (the integer portion of) each number taken as a whole. So far so good... In the case of "123.45" & "234.56", the two values are evaluated character-by-character according to the ASCII values of each character. So, while the previous case only works with numbers, in this case you could just as easily say "ABCD" & "gHiJ". I won't reproduce the entire ASCII table, but here are the values for the numerical digit characters. And while we're at it, lets show their binary representations. We will need them in a minute.
Note in each case we are talking about e.g. the character 7. Not the value seven (as in seven things). So... when Perl sees "123.45" & "234.56", it takes each string character-by-character comparing (so to speak) their binary representations. So, for the first character of each string:
For the second character of each string:
And so on until we get "020.44". Now the folks who designed the ASCII table did a clever thing. They set up the table so that the bottom four bits of the number characters were also the binary values for each digit. So for the character '5':
and for the value five (as in five things): 5 = 0101 binary so when we start ANDing and ORing these they act as if we were ANDing and ORing each digit's value (and not simply its ASCII assignment) digit-by-digit. If we do bitwise comparisons of strings of digits, we can (within certain limits) pretend we are ANDing or ORing the values of each digit and not just their ASCII assignments. Cute! But watch out. If you say "1234" & "39", Perl will start with the left-most character in each string. It will not compare the tens digit against the tens digit. So what good is all this? Danged if I know!... Actually I can think of a few uses. Here's one example. First, some more ASCII values:
Note that 'A' and 'a' differ by 32. And as chance would have it, ASCII character 32 (which is the space character: ' ') has a binary representation with just one single '1' bit set. This means that it makes a useful binary mask (those clever ASCII people again). And the complement of character 32 (for our purposes) is character 95 which is the underscore. So here are a pair of clumsy upper- and lower-case translators: Which prints:
And that, I suppose, is quite enough about bitwise comparison of strings for now... HTH Update: Many of the responses to this thread play around with the upper/lower-case trick. | [reply] [d/l] [select] |
|
Re: bitwise operators
by wog (Curate) on May 28, 2001 at 04:24 UTC | |
In this case, under the ASCII charset the strings "123.45" and "234.56" are represented by the bits: 1 2 3 . 4 5 00110001 00110010 00110011 00101110 00110100 00110101 2 3 4 . 5 6 00110010 00110011 00110100 00101110 00110101 00110110Thus when AND'ing them together you keep all bits which are 1 in both things as 1, and everything else becomes 0 resulting in the string "020.44" represented in ASCII with: 0 2 0 . 4 4 00110000 00110010 00110000 00101110 00110100 00110100All this is probably not portable to systems with odd charsets like EBCDIC. Now, if we were to AND together numbers (not strings) like say 123 and 234, we'll get a completely differnt result. For example, the numbers 123 and 234 and represented by: 123 01111011 234 11101010Note that this is different then AND'ing together strings since we're working with numbers, not charactors. Thus the result is 106, represented by: 01101010 Another thing to note is that if you try to have perl and together non-integers like doing 123.45 & 234.56, perl appears to treat 123.45 and 234.56 as if we used int(123.45) and int(234.56), which avoids odd situations you'd get if you tried to AND floating point numbers together, because they're implemented in a way that varies greatly from machine to machine. All bit strings here were generated with unpack "B*", ..., so have most signifigant byte first. | [reply] [d/l] [select] |
|
Re: bitwise operators
by srawls (Friar) on May 28, 2001 at 03:55 UTC | |
These are the binary representation of two numbers. Now, we go through bit by bit and we take the result by these rules: so, the above is this: There are also the operators OR,XOR,and more. OR is the result bit is 1 if either bit is set, XOR is the result bit is 1 if one but not both of the bits are set. The 15 year old, freshman programmer, Stephen Rawls | [reply] [d/l] [select] |
|
Re: bitwise operators
by mr.nick (Chaplain) on May 28, 2001 at 04:16 UTC | |
| [reply] |
|
Re: bitwise operators
by tigervamp (Friar) on May 29, 2001 at 07:53 UTC | |
1. Cryptography Bitwise Operators can play a very important role in cryptographic/masking algorithms. For example, say that you had a piece of binary data, for simplicity, these 15 bytes: This is a test. You also have a 15 byte "mask", a string of random bytes, the same length as the length of the string to be masked. Again, for simplicity, lets say the (obviously not very random) mask is: abcdefghijklmno To encode the orginal data, you would apply the mask "abcdefghijklmno" to the data "This is a test." You would do this by using the XOR bitwise operation. THE XOR OPERATOR The XOR operator works on bits in the same ways as explained in previous responses. The XOR test is true(1) if the two bits that are being compared are different(1 and 0), or false(0) if they are the same. Therefore, performing the XOR operation on the following 2 bytes would work as shown:
10010111
01011100
You get the original piece of data back!
2. Internal data structures Mastering Algorithms with Perl -- Explains the use of bit vectors in mathematical algorithms and Encrypting data using the XOR method I discussed. http://www.cs.cf.ac.uk/Dave/PERL/node36.html -- Discusses bitwise operators including bitwise shifts Programming Perl -- General information about bitwise operations, probably the book you are already reading
CPAN also has some interesting/useful modules including Tie::VecArray and Bit::Vector.
Hope this helps,
| [reply] |
by mattr (Curate) on May 29, 2001 at 15:42 UTC | |
But to keep it simple, I always remember
That's because with single-digit binary numbers, AND gives you the same result as multiplication and the same goes for OR and addition. (A truth table, which shows the grid of all possible pairs and the result you get for a given operation, is helpful.) Understanding binary is good in Perl when you want to check the return value of a system function, since it may look like 128 for example but you know it is just the 8th bit that is set to 1. You can shift that bit left or right to simulate multiplication or division by two. Binary logic is also the fundamental idea behind the operators "and", "or", "|", "||", "&", and "&&". If you ever use all capitals constants for system control you are probably using binary without realizing it. You also need to know what you are doing here when you tie a database or use other routines that let you hand them a number of boolean (single bit) flags. Also if you are doing Perl in windows or talking to a C program, you may very well need to set "flags" or use a "bit mask". For example, say you have a window drawing function and it treats each bit of an argument as a display option. Perhaps the second bit means "the window has beveled edges" and the fourth bit means "vertical scrollbar should be displayed". Then you would want to set both bits to specify both options, in other words take a string of 8 zeroes and set the second and fourth bits to ones (usually we count right to left so the first bit is on the right). In base two you get 00001010 (in base two, or binary) or 2^1 + 2^3 = 2+8 = 10 (in base 10). Now If you got the current setting and it was 8 (scrollbar displayed) and you wanted to add bevelled edges, you could add (binary OR) that value (8, or in binary 00001000) with your bit mask (10, or in binary 00001010). Since OR is like addition, it makes sense that every digit set to one in your mask will become set. Likewise, if you had used AND, every bit set to zero in your mask would be cleared because anything AND 0 is like multiplying. by zero. Usually these display options are given all capitals names like V_SCROLLBAR and BEVELED_EDGE. Then if you have a function DrawWindow that takes three bytes (x, y, and type) as arguments, you can draw a window at coordinates x and y with something like DrawWindow(x,y,V_SCROLLBAR|BEVELED_EDGE). So the more bits you have, the more options you can set. This is really the front end for the C or C++ code in which the function was originally written, and the byte size of each argument is predefined. This means that you can only specify up to eight window options at once if type is only one byte long. So you may see a function called something like DrawWindowEx which might be a function that might allows many more settings because it had a 32 bit (4 byte) argument. Another example is this snippet from DB_File.pm:
sub LOCK_SH { 1 } ... unless (flock (DB_FH, LOCK_EX | LOCK_NB)) { .... } That means a file lock on the file handle DB_FH is being requested and that the lock should be both exclusive and nonblocking. Unless flock returns a number greater than 0, the .... code is executed.
$db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0644)
You see someone (Paul Marquess, writer of that module) was trying to tie a hash variable (db) to a file (foo.db) using the DB_File module and opening the database file with file creation and Read/Write permission. In the last line of code above, you see bitwise OR (single pipemark) being used to add two flags, and you also see logical OR (double pipe, synonymous with "or") which will cause the "die" code to be executed if Perl decides it needs to look at it to evaluate the entire line. It is neat that "die" is not looked at if what comes before the double pipe is true, since in bitwise addition you already know the answer if you can tell the first value of your pair of binary digits is true (i.e. set to one). So binary logic is pretty important in Perl! By the way if you are curious what kind of constants are out there, you can check out Fcntl.pm, or (in unix) try "man fcntl" to see what the values are on your system. A Windows programmer's guide will also be full to the brim with these all caps flags. | [reply] |
|
Re: bitwise operators
by sir p freakly (Initiate) on May 28, 2001 at 08:25 UTC | |
| [reply] |
by shotgunefx (Parson) on May 28, 2001 at 09:27 UTC | |
Around the early 90's when I was writing 3D texture mapped engines designed for 386/386sx+ systems (16 Megahertz!), I used them constantly. You can use bitshifts and bitlogic to do quick (and dirty) multiplies/divides by powers of 2, cheap modulus operations, collision detection, etc. Under those constraints, every clock cycle counts. At that time, you had to roll your own video drivers which meant screwing around with SVGA registers (all bit-masking)and all other arcane kind of things. That said, if you are doing system level programming you will probably use them quite often. To be honest, I haven't ever had the need (yet) to use them in any Perl applications. -Lee "To be civilized is to deny one's nature." | [reply] |
by Anonymous Monk on May 29, 2001 at 03:05 UTC | |
#var1= 0011 var2 = 1100 (only stating last # 4 bits, of cousre) $var1 ^= $var2; # v1=1111 $var2 ^= $var1; # v2=0011 $var1 ^= $var2; # v1=1100 | [reply] |
by rchiav (Deacon) on May 28, 2001 at 09:06 UTC | |
You can take a 32 bit int and set one of the bits. Setting the 4th bit would make the integer value 8. Now why would you want to do this? A good example of this would be the data that stored in Windows NT domain accounts. I use this example because its the most recent thing I've used bitwise operators for. If you look at NT accounts, there are several "toggles" for things like "Account Locked Out", "User Must Change Password", "User Cannot Change Password", etc... Instead of storing all of these in seperate variables, they are all stored in one integer. And if you want to test to see if the users account is locked out or unlock the account, you can test for that bit or toggle the bit, respectivly. In smaller programs, it's probably not something that you're going to want to use. But if you're talking about a bunch of simple yes/no variables that are going to be replicated over and over again (like for accounts), you're going to save space, and I belive slightly improve speed by storing them in an integer as on/off bits.
Hope this helps... | [reply] |
by wog (Curate) on May 28, 2001 at 09:30 UTC | |
To my knowledge, doing that is actually slightly slower in most cases. This is because if you're storing it as an integer one operation must be done to retrieve it: get value from location in memory; and to store it: store value to location in memory. On the other hand, with indiviual bits there are more operations; to get a bit value: get 32 (or whatever) bit value from memory, and then use AND to check the bit's value; and to store: get value from memory, use OR or AND or XOR to set or toggle the bit in question, and then store the value in memory. But it's probably unlikely that the speed difference will matter in most cases. I'd expect that usually the speed tradeoff is well worth the space advantage (update:) Thinking about this more makes me think it more of a toss-up. You probably would have a speed improvement if you would otherwise have to get lots of values from memory, because that is relatively "slow". If you're just doing something like going through a bunch of these numbers to check for one or two bits, or to set one or two bits, the way of using lots of numbers will probably be faster, I think. But if you're just using one number for a bunch for a bunch of things you're using a runtime, I'd guess that it would be faster because you could actually keep the value in one register, or it would be easier to cache it. (With perl, we probably don't have any hope of it staying in a register, so the cache is your only hope; and the cache might just as easily cache 32 32-bit values, too.) (All this is of course IMO, and subject to being totally wrong.) | [reply] |