views:

428

answers:

6

Possible Duplicate:
Generating Random Numbers in Objective-C

How do I generate a random number which is within a range?

+1  A: 
int rand_range(int min_n, int max_n)
{
    return rand() % (max_n - min_n + 1) + min_n;
}

For fractions:

double rand_range(double min_n, double max_n)
{
    return (double)rand()/RAND_MAX * (max_n - min_n) + min_n;
}
Michał Trybus
This will not give a uniform distribution (except for powers-of-two).
Oli Charlesworth
I know, but it works fast, and the distribution is ok for small ranges. It is good for gamecoding. Anyway, I should have written this somewhere in the answer.
Michał Trybus
@Oli who cares? See Ukko's comment in the answer above. If you are using rand() to begin with, the teeny amount of skew (for max_n-min_n relatively small) is the least of your worries.
@user168715: Because this approach will not map onto decent random-number implementations where this skew may well matter.
Oli Charlesworth
+1  A: 

http://www.cprogramming.com/tutorial/random.html

The second example shows how to generate by range

Tom Gullen
+5  A: 

This is actually a bit harder to get really correct than most people realize:

int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
 */

    int divisor = RAND_MAX/(limit+1);
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval > limit);

    return retval;
}

Attempts that just use % (or, equivalently, /) to get the numbers in a range almost inevitably introduce skew (i.e., some numbers will be generated more often than others).

Edit: as to why using % produces skewed results: unless the range you want is a divisor of RAND_MAX, skew is inevitable. If you start with small numbers, it's pretty easy to see why. Consider taking 10 pieces of candy and trying to divide it evenly between three children. Clearly it can't be done -- if you hand out all the candy, the closest you can get is for two kids to get three pieces of candy, and one of them getting four.

There's only one way for all the kids to get the same number of pieces of candy: make sure you don't hand out the last piece of candy at all.

To relate this to the code above, let's start by numbering the candies from 1 to 10 and the kids from 1 to 3. The initial division says since there are three kids, our divisor is three. We then pull a random candy from the bucket, look at its number and divide by three and hand it to that kid -- but if the result is greater than 3 (i.e. we've picked out candy number 10) we just don't hand it out at all -- we discard it and pick out another candy.

Jerry Coffin
I'm sorry, but ewww! The last thing I want to do is loop a divide an indeterminate number (who knows, perhaps forever) of times when trying to get a random number. Skew or not, I'll take simpler or perhaps a table driven solution over this.
Michael Dorgan
@Michael: try it before yo jump to any conclusions. In fact, the "indeterminate number" is *usually* 1. Unless you do this in a *really* tight loop (e.g., filling a vector with random numbers) it's virtually impossible to even measure this being slower than the versions that are clearly wrong.
Jerry Coffin
This is technically correct but you have a GIGO problem starting with rand(). It looks like you are trying to correct the skew when limit is not a factor of RAND_MAX, using the modular division approach your error is on the order of `limit / RAND_MAX` until `limit` approaches `RAND_MAX`. The problems starting with a PRNG like Rand() dwarf effects like that. The price you pay is to introduce a non-derterministic loop with unbounded run time [IRL it runs once but we are splitting hairs here ;-)] and you gain nothing because Rand is crap to begin with.
Ukko
No, no, I get why the others are wrong and this is a good solution. But, I come from embedded land where divides, until recently, were ouch slow. Combine that with a rand() call that also tends to be on the slow side (not to mention unrandom enough that looping off them gives me a bad feeling in my stomach) and you can see where I stand. I also worried at first glance that this may not be deterministic, but it is. Bah, just gotta get used to coding in the 21st century here.
Michael Dorgan
"Attempts that just use % (or, equivalently, /) to get the numbers in a range almost inevitably introduce skew (i.e., some numbers will be generated more often than others)." That's news to me. I'm not saying it's wrong (who am I to debate with 33.7k rep), but just that factoid never came up in my own research, nor have I seen any issues based on my own casual observation.
Philip Regan
@Ukko:`rand()` may be poor. Then again, it may not be; I've used an implementation where it was the Mersenne Twister, which is pretty decent.
Jerry Coffin
@Philip Regan: The Skew comes from the little remainder after the modulus is taken. Lets say your random number generator generates 11 values 0 - 10 then you use use these number mod 5 to give you a number between 0 and 4. There are two ways to get a 3 (3 and 8) but three ways to get a 0 (0, 5, 10) so the end result is not uniform. It is a real effect, but one I argue is lost in the noise of other larger problems of using PRNGs.
Ukko
@Jerry and @Ukko: Thanks for the explanations. They make perfect sense. Looks like I have a little updating to do. Cheers!
Philip Regan
@Jerry Coffin: I would still argue that even with the MT generator this would not be the right thing, even though you have reduced the GIGO problem. But it really is a matter of what offends your coding sensibilities the most I guess.
Ukko
@Jerry on Mac OS X, rand() is poor. In particular, the bottom 12 bits go in a cycle. You should at least use random()
JeremyP
A: 

I wrote this specifically in Obj-C for an iPhone project:

- (int) intInRangeMinimum:(int)min andMaximum:(int)max {
    if (min > max) { return -1; }
    int adjustedMax = (max + 1) - min; // arc4random returns within the set {min, (max - 1)}
    int random = arc4random() % adjustedMax;
    int result = random + min;
    return result;
}

To use:

int newNumber = [aClass intInRangeMinimum:1 andMaximum:100]; 

Add salt to taste

Philip Regan
A: 

For an integer value in the range [min,max):

double scale = (double) (max - min) / RAND_MAX;
int val = min + floor(rand() * scale) 
John Bode
A: 
+(NSInteger)randomNumberWithMin:(NSInteger)min WithMax:(NSInteger)max {
    if (min>max) {
        int tempMax=max;
        max=min;
        min=tempMax;
    }
    int randomy=arc4random() % (max-min+1);
    randomy=randomy+min;
    return randomy;
}

I use this method in a random number related class I made. Works well for my non-demanding needs, but may well be biased in some way.

Tom H