Question

Using PHP (other languages, using common built-ins are welcome), how can I get a random (or pseudo-random) number that does NOT match a certain criteria?

IE: I want $x = rand(0, 99) but only if ($x % 9) != 0.

What is a clean acceptable way to constrain random numbers to a criteria like that?

As an example, using a while() loop, and possibly breaking when we have something that meets our criteria, then using the random number after the loop?:

while ( ($rand_key = array_rand($array_of_items)) && ($rand_key % 9 == 0) ) 
{ 
    // Do nothing?
}

Or something like:

while ( $rand_key = array_rand($array_of_items) ) 
{ 
    if ( $rand_key % 9 == 0 ) {
        break;
    }
}

Or is there a more concise or appropriate way to accomplish this?

Was it helpful?

Solution

One of the rare cases where a do-while loop actually helps

$testData = array( 7, 8, 9 );

do {
  $rand = array_rand( $testData );
} while ( $testData[$rand] % 9 == 0 );

echo $testData[$rand];

OTHER TIPS

Is that your exact usage case, or just an example?

If you're trying (in particular) to get numbers from 0 to 99 excluding exact multiples of 9, I can think of a couple of ways to avoid the awkward looping. People don't like to loop while generating random numbers because you could loop forever. (But of course that won't happen unless you're the extremely unlucky type--the sort of person who happens to get himself in gunfights with Clint Eastwood in spaghetti westerns.)

  1. You could have a lookup table that remaps the random numbers you get into the ones you want.

  2. Generate 0-88 randomly. Multiply the result by 9 and divide it by 8 and get the integer result (floor, not round). Then add 1.

Both of these have predictable timing.

An alternative method, that trades space for, potentially, multiple PRNG calls, for cases with small numbers of valid results (as in your example) would be to populate an array with the valid solutions and use the PRNG to produce an index into the array.

Whatever method you choose I'd also suggest, for production code, noting the reason for the restriction in an appropriate and accessible way.

This matches the 'concise' requirement:

while( ($x = rand(0, 99)) % 9 == 0 );
echo $x;

or

while ( $array_of_items[$rand_key = array_rand($array_of_items)] % 9 == 0 ); 
echo $array_of_items[$rand_key];     

However, it isn't very readable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top