Originally posted by Installer
Good one. Off the top of your head, was that?
No.
while ($total < 1) {
$key = mt_rand(0, count($fractions) - 1);
$tmp = $total + $fractions[$key][1];
if ($tmp > 1) {
continue;
In the above snippet, on the third and subsequent iterations, wouldn't it be possible for $key to continually select too big a value?
Say, your first random fraction is 1/2, and the second is 1/4. It seems to me that it's possible for the random function above to generate 1/2 as the third value. This will be ignored, so it selects another. What if that's 1/2 again? and again? and again?
That's pretty unlucky, but it gets more and more possible as the thing is extended.
Suppose that the random sequence of
1/8, 1/4, 1/8, 1/4, 1/16, 1/8 is generated. The only valid next fraction in order to generate a value of 1 is 1/16. Assuming even distribution from the mt_rand function, and assuming my memory of these things is correct, it would take, on average, 2.5 iterations through the loop to fill that last slot. If you're lucky you might get it in the first shot. If you're unlucky, it might take you 10 goes. If you're very. very unlucky, you might never get it.
That's where the potential infinite loop comes from.
The algorithm I used takes the trouble to only make available for selection for any slot, the allowed values for that slot - ie the ones that won't take it over the target. So, if a random sequence of 1/8, 1/4, 1/8, 1/4, 1/16, 1/8 had been generated, only 1/16 would be available for selection, so you would be guaranteed to get it. No chance of an infinite loop taking you off.
I'm not saying it's likely, just possible. And my own experience is that if you make it possible for bad things to happen, they will eventually.
It's a small thing and I never wanted to overstate it, hence my original references to "just a smidgeon more intelligent" and "infinite loops which your code could fall into".
I do compliment the tightness of your code. I'm sure you could address the above and still not need as much code as I used.
One thing which I would change in my own code if I was to use it myself would be to remove the decimal element from each of the arrays in $fraction, and remove the quotes from the fractional element. The fractional elements are never needed as strings, and the overhead of calculating the decimal values from the fractional isn't hugely signifigant.
I would also wrap it up a bit nicer. Perhaps as a function as you suggest, or maybe as a method on an object. But the point of this was just to show how I would approach the logical problem.
Also, just FYI, if octavarium is using a version of PHP older than 4.2.0, then the random seeding should be used, even with mt_srand.
And speaking of octavarium, thanks for the interesting challenge. 🙂 I hope this thread has given you some good food for thought. Best of luck in your PHP adventures.
OK, I'm out of here. The world doesn't need another post from me on this topic.