View Full Version : & number
jscheuer1
07-27-2012, 04:00 AM
I was just helping out someone in this forum with a syntax error. That went OK, but their code also had something in it that I don't understand:
$bigIndex = rand(0, (count($quotations) -1)) & 65534;
I get that it's setting the var $bigIndex to a random number based upon the length of the $quotations array. What I don't understand is the exact meaning of the:
& 65534
part.
It appears to make it so that the number returned is even, and it appears that it at least allows that number to be within the range specified by:
0, (count($quotations) -1
without going over, even though that range is less than and is far lower than 65534.
Anyone can tell me what it means?
james438
07-27-2012, 05:04 AM
At first glance it looks like a unicode value. The range goes from 0 to 65535 and is expressed like this:
<?php
echo "xx&# 65533;xx<br><br>";
?>
I used 65533 as it is the last one that you can use. 65534 and 65535 are reserved and not to be used. ref (http://www.4d.com/docs/CMU/CMU10039.HTM)
EDIT: There is not really a space between the # and 65533, but I added it because this forum expresses unicode as actual unicode even if it is placed in PHP tags.
jscheuer1
07-27-2012, 07:08 AM
I think you're on to something, because if I use 65536, which you say is out of range, $bigIndex is always 0. That would tend to indicate that the expression is a bitwise comparison that returns a number and that 65536 is false.
I do know that in this case it is somehow assuring that $bigIndex must be even and that it can at least be as high as the total number of entries in the array, yet no higher.
If I remove it entirely:
$bigIndex = rand(0, (count($quotations) -1));
$bigIndex can be odd. If I use a lower number (here the actual length of the array):
$bigIndex = rand(0, (count($quotations) -1)) & 572;
$bigIndex has to be even again but now cannot be more than a certain amount, though since it's random, I'm not sure exactly, but it's obviously much less than the number used.
So it obviously set a limit. If the number is odd, then $bigIndex can be even or odd.
So I basically understand its function here. Just not what it's called or how it's working.
In simplest terms, it rounds down to the nearest even number.
james438
07-27-2012, 07:34 AM
There may be a reason for the even/odd setting, but I wonder if it is an error in his code. It depends on what he is trying to do, though.
It might be interesting to create a tiny script that will randomly generate a small set of unicode characters, but there are still very large gaps in unicode that have not been assigned yet.
EDIT: Silly me. The name of the string itself is $quotations, so it probably has to do with some sort of counting or generating of sets of quotation marks, which would always be an even number.
djr33
07-27-2012, 07:52 AM
It's a bitwise operator. 65536 is 16^4 or 2^16.
Unfortunately I've never had the need to understand how to use bitwise operators so I don't really understand them. Here's the php.net page though:
http://php.net/manual/en/language.operators.bitwise.php
It looks like the goal is to retain all bits in the random number that also correspond to a large power-of-2 number-- the goal seems to be finding a number that is a power of 2 (or is it just divisible by two? I'm not sure). Since 2^16 is a very large number, it effectively does this even though technically there are larger numbers (but not relevant in this case).
jscheuer1
07-27-2012, 07:54 AM
$quotations is an array of quotations and attributions. The quotations are even numbers the attributions are odd. The entire function returns the $bigIndex followed by the $bigIndex + 1. So as long as the number returned is even, you get a quote followed by it's author. If the expression:
$bigIndex = rand(0, (count($quotations) -1)) & 65534;
returns an odd number, which it can if we remove the bitwise operation, then the author is listed first, followed by the next quotation.
So, again in simplest terms, it's rounding down to the next even number.
I tried it with actual numbers. That's what it does. As to why it does that, and what it's called, that's what I want to know. I think I have my second answer. It's a bitwise operation. How it does what it does here is still a bit opaque to me.
In the PHP manual it says:
Example Name Result
$a & $b And Bits that are set in both $a and $b are set.
So it's staring me in the face, I'm just not seeing it.
djr33
07-27-2012, 08:00 AM
I think we posted at the same time, John.
I'm not sure I exactly get it either, but it's close enough. Bitwise operators are very low level so they are processed quickly and are very efficient for simple mathematical operations. (I find them almost impossible to read, but that's irrelevant.) So it's just a trick to get an even number (since that's what your tests show), using the comparison of a known even number.
But I didn't notice above that it's 65534 not 65536, so I don't know what's going on there. Maybe there's a 0 implicit so it's really 65535 (as in array indices), but then I don't know there that one extra 1 is going.
jscheuer1
07-27-2012, 08:21 AM
It's a bitwise operator. 65536 is 16^4 or 2^16.
What you're saying there makes sense. I had figured out it was a bitwise operator, but not how it was doing what it was doing. That and the rest (quoted below) adds a clue, enough of one that I feel I've almost got it.
It looks like the goal is to retain all bits in the random number that also correspond to a large power-of-2 number-- the goal seems to be finding a number that is a power of 2 (or is it just divisible by two? I'm not sure). Since 2^16 is a very large number, it effectively does this even though technically there are larger numbers (but not relevant in this case).
The only thing is that it's 65534. If it's 65536, it's out of range somehow (almost certainly because it has something to do with Unicode) and always returns false/0.
If it's 65535, it's in range, but can be either even or odd, so has no discernible effect.
By experimenting though, if the number is too low, it limits the upper range of the result. So the bits being shared is somehow the key. I guess I need more info on just what a bit is in this case, and on how Unicode ties in.
It smells like a special case and/or trick with math and/or something that relies upon a limitation of PHP sort of thing.
If I do:
$bigIndex = 571 & 65532;
I get 568. But with (or 65530, strangely):
$bigIndex = 571 & 65534;
I get 570 - the desired result in this case. So it looks like a Swiss cheese effect.
djr33
07-27-2012, 08:32 AM
Hm, I wonder if the fact that it's 65536-2 = 65534 is relevant. That is: it's exactly 2 less than 2^16. Maybe those bits line up in a certain way that includes all lower bits involving 2?
Hmm... binary would be something like this:
00010 = 2
00100 = 4
00110 = 6
01000 = 8
01010 = 10
01100 = 12
01110 = 14
10000 = 16
At 14, all bits are set except (the first* and) the last. In other words, this looks like it's allowing any and all 2-multiple value bits (that is: anything above the first '1' value bit), thereby requiring an even number is set.
(*The first is irrelevant because it would be a higher number than necessary and there are always infinitely many more higher numbers available, so at some point you must stop.)
Does that look correct to you? I'm still puzzled by it. But it's definitely a math trick that relies on how PHP does all of this (but I think it's a strategy used in C++ too, but I'm not positive about that).
I feel like there should be a cleaner way to do this using the numeral '1' instead of '65534'. Remove those bits that match '1', rather than keeping only those that match '65534'.
Aha... here it is:
$a & ~1
At least in theory I think that should work. Or something like it.
jscheuer1
07-27-2012, 08:51 AM
Yep, that ($a & ~1) seems to work:
$bigIndex = rand(0, (count($quotations) -1)) & ~1;
It has the added advantage of nothing being out of range. Like:
$bigIndex = 65536 & 65534;
is 0, while:
$bigIndex = 65536 & ~1;
is 65536.
Still doesn't explain why 65536 is out of range, though Unicode gives a clue on that.
djr33
07-27-2012, 08:59 AM
Unicode isn't related to this at all (except that it, like other information, is stored in a binary format). I believe it's "out of range" simply because there are fewer than 65536 quotations in the list ;)
The trick is to get all of the 2-multiple bits set (~1 does this, as does [2^N]-2), then only allow those 2-mulitple bits in whatever random number was generated. It's clever.
The only reason I can think of using 65534 instead of ~1 would be that it might process a little faster, whereas ~1 is much easier to remember/type. But that will include the entire range up to the largest possible [2^N]-1 value, BUT only as bits which is [very] much faster than actually calculating any of that using traditional math. Intriguing.
Note that this only works for even [or odd] numbers though, because this is base 2. If it were base 3, it would work for numbers divisible by 3, etc. But computers are binary, so this is merely a shortcut for one very specific case: divisibility by 2.
james438
07-27-2012, 09:18 AM
Can I see a link to the code you are working with?
jscheuer1
07-27-2012, 09:57 AM
It's not out of range because of the reason you state. Using just raw numbers:
65536 & 65534
is 0, while:
65536 & ~1
is 65536.
A link would be pointless, all you would see is a random quote, it's PHP.
Here's a simplified version (only 2 quotes) that shows all you need to see what's what:
<?php
$quotations = array(
"This is quotation one",
" ",
"This is quotation two.",
"North Carolina G.S. 90-210.25(c)(9)",
);
$noAuthor = " ";
$bigIndex = rand(0, (count($quotations) -1)) & 65534; // or $bigIndex = rand(0, (count($quotations) -1)) & ~1;
echo "<br /><br /><div class='quotations'> {$quotations [$bigIndex]} <br /><br /><div align='right'>";
if ($quotations [$bigIndex + 1] != $noAuthor) {
echo "- {$quotations [$bigIndex + 1]}";
}
echo "</div></div>";
?>
And really, all you need to play with the concept under discussion here is:
<?php
$bigIndex = rand(0, 571) & 65534; // or $bigIndex = rand(0, 571) & ~1;
echo "$bigIndex";
?>
You can play with the numbers and see what you get. You can substitute various actual numbers for rand(0, 571) to have more control over the situation and thereby perhaps get more information from the results.
jscheuer1
07-27-2012, 12:52 PM
I since got out the programmer's calculator and lo and behold, 65534 is:
1111111111111110
Notice the first bit is 0. All odd numbers have a 1 there, so that's a key clue.
But why it compares favorably with - say 568:
1000111000
I'm not sure. It looks like - if a bit exists in the number on the left ($a), it must also exist in the number on the right ($b):
$a & $b
If it doesn't, that bit gets knocked out of the number on the left.
If so, ~1 might be more efficient because it only checks the first bit, If it's one, it knocks it out, otherwise it leaves the number alone. With 65534, it might have to check each bit of the number on the left only to find that they're (in the case of an even number) all cool. With an odd number it might have to check them all as well to make sure other bits might not have to be knocked out.
That still doesn't explain why 0 is the only valid result of comparing with 65536.
Oh, yes it does as 65536 is:
10000000000000000
So one should (and a quick test shows that one can) be able to use:
262142, which is:
111111111111111110
In which case it has nothing to do with Unicode, that part was just a coincidence.
And for an array containing no more than 572 entries, 1022:
1111111110
would be sufficient.
And now it makes perfect sense to me when PHP.net says:
Bits that are set in both $a and $b are set.
That's exactly what's happening. Whew!
marain
07-27-2012, 02:32 PM
65534 (as you discerned) forces the number to be even. In binary, it is all 1's, except for the last bit, which is 0, thus forcing the rounding down. Using 65534 maximizes the number of entries in the array for two bytes. 254 would work if the number of entries was a (binary) number that could fit into a single byte.
jscheuer1
07-27-2012, 02:37 PM
Using ~1 maximizes for unlimited bytes.
marain
07-27-2012, 05:53 PM
I'm not going to live long enough to exceed the 65534 that the script can presently accommodate ;)
A.
jscheuer1
07-28-2012, 02:48 AM
That's a little misleading, but probably still essentially accurate.
In any case I hope you live a long time.
My point though is that the number used to check must be much higher than the number of entries. Currently there are 572. To properly check all those requires at least 1022. Using ~1, one need not concern oneself with what number is required. And though I'm not certain, I think ~1 is more efficient.
Powered by vBulletin® Version 4.2.2 Copyright © 2021 vBulletin Solutions, Inc. All rights reserved.