views:

43073

answers:

5

I'm a java head mainly, and I want a way to generate a pseudo-random number between 0 and 74. In java I would use the method:

Random.nextInt(74)

I'm not interested in a discussion about seeds or true randomness, just how you accomplish the same task in Objective-C. I've scoured The Google, and it just seems to be lots of different and conflicting bits of information.

+33  A: 

Same as C, you would do

#include <stdlib.h>
...
int r = rand() % 74

(assuming you meant including 0 but excluding 74, which is what your Java example does)

Edit: Feel free to substitute random() or arc4random() for rand() (which is, as others have pointed out, quite sucky).

-1. You need to seed the random number generator or you will get the same pattern of numbers on each execution.
Alex Reynolds
How about I want to start from a different number than zero?
amok
Don't forget time.h!
thyrgle
@amok: You can just add the number that you want to start from to the result
Florin
I keep getting the number 9. Pretty random I'd say ;D
alexy13
+11  A: 

According to the manual page for rand(3), the rand family of functions have been obsoleted by random(3). This is due to the fact that the lower 12 bits of rand() go through a cyclic pattern. To get a random number, just seed the generator by calling srandom() with an unsigned seed, and then call random(). So, the equivalent of the code above would be

#import <stdlib.h>
#import <time.h>

srandom(time(NULL));
random() % 74;

You'll only need to call srandom() once in your program unless you want to change your seed. Although you said you didn't want a discussion of truly random values, rand() is a pretty bad random number generator, and random() still suffers from modulo bias, as it will generate a number between 0 and RAND_MAX. So, e.g. if RAND_MAX is 3, and you want a random number between 0 and 2, you're twice as likely to get a 0 than a 1 or a 2.

Michael Buckley
You might as well call srandomdev() instead of passing the time to srandom(); it's just as easy and mathematically better.
benzado
+57  A: 

You should use the arc4random() function. It uses a superior algorithm to rand. You don't even need to set a seed.

#include <stdlib.h>
...
...
int r = arc4random() % 74;

The arc4random man page:

NAME
     arc4random, arc4random_stir, arc4random_addrandom -- arc4 random number generator

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <stdlib.h>

     u_int32_t
     arc4random(void);

     void
     arc4random_stir(void);

     void
     arc4random_addrandom(unsigned char *dat, int datlen);

DESCRIPTION
     The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8
     bit S-Boxes.  The S-Boxes can be in about (2**1700) states.  The arc4random() function returns pseudo-
     random numbers in the range of 0 to (2**32)-1, and therefore has twice the range of rand(3) and
     random(3).

     The arc4random_stir() function reads data from /dev/urandom and uses it to permute the S-Boxes via
     arc4random_addrandom().

     There is no need to call arc4random_stir() before using arc4random(), since arc4random() automatically
     initializes itself.

EXAMPLES
     The following produces a drop-in replacement for the traditional rand() and random() functions using
     arc4random():

           #define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))
lajos
A: 

I get negative numbers from arc4random, so I have to use abs(arc4random()) in my result which obviously defeats some randomness. Why??? I thought the range was within 0..INT_MAX not INT_MIN...INT_MAX.

    for( int j=0; j<10; j++ ){
 int r = arc4random();
 NSLog(@"%s \t%d \t%d \t%d", (r>=0) ? "++++" : "----", j, r, r % 10);
}
assert(0);

generates the following output:

2009-10-17 11:15:22.737 Fortune[1281:207] ++++ 0 987748783 3

2009-10-17 11:15:22.758 Fortune[1281:207] ---- 1 -81091275 -5

2009-10-17 11:15:22.771 Fortune[1281:207] ++++ 2 98279690 0

2009-10-17 11:15:22.784 Fortune[1281:207] ---- 3 -694992398 -8

2009-10-17 11:15:22.796 Fortune[1281:207] ++++ 4 1467322001 1

2009-10-17 11:15:22.808 Fortune[1281:207] ++++ 5 1282335903 3

2009-10-17 11:15:22.820 Fortune[1281:207] ---- 6 -379255192 -2

2009-10-17 11:15:22.832 Fortune[1281:207] ++++ 7 202687027 7

2009-10-17 11:15:22.841 Fortune[1281:207] ---- 8 -1099161751 -1

2009-10-17 11:15:22.850 Fortune[1281:207] ++++ 9 2105903055 5

mobibob
You are assigning an uint32_t (the return value of arc4random, it's an unsigned type) to an int, which is signed. This is correct behavior. Had you read the manual quote posted by lajos thoroughly, you would have also seen the following: EXAMPLES The following produces a drop-in replacement for the traditional `rand()` and random() functions using `arc4random()`: `#define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))`
MrMage
I did read when I was studying the post but overlooked it when I was reviewing my implementation. Thanks for pointing that out and sorry for the trivial post, but my eyes are getting lazy.
mobibob
This is really a separate question isn't it? The answer is wrong anyways because it still shows `int r = arc4random();`
bentford
+2  A: 

I wrote my own random number utility class just so that I would have something that functioned a bit more like Math.random() in Java. It has just two functions, and it's all made in C.

Header file:

//Random.h
void initRandomSeed(long firstSeed);
float nextRandomFloat();

Implementation file:

//Random.m
static unsigned long seed;

void initRandomSeed(long firstSeed)
{ 
    seed = firstSeed;
}

float nextRandomFloat()
{
    return (((seed= 1664525*seed + 1013904223)>>16) / (float)0x10000);
}

It's a pretty classic way of generating pseudo-randoms. In my app delegate I call:

#import "Random.h"

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    initRandomSeed( (long) [[NSDate date] timeIntervalSince1970] );
    //Do other initialization junk.
}

Then later I just say:

float myRandomNumber = nextRandomFloat() * 74;

Note that this method returns a random number between 0.0f (inclusive) and 1.0f (exclusive).

Eli