754

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 Google, and there just seems to be lots of different and conflicting bits of information.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rustyshelf
  • 44,963
  • 37
  • 98
  • 104

13 Answers13

1036

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

#include <stdlib.h>
// ...
// ...
int r = arc4random_uniform(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))
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
lajos
  • 25,525
  • 19
  • 65
  • 75
  • 97
    Use `arc4random_uniform(x)` as described below by @yood. It is also in stdlib.h (after OS X 10.7 and iOS 4.3) and gives a more uniform distribution of the random numbers. Usage `int r = arc4random_uniform(74);` – LavaSlider Jan 16 '12 at 16:12
  • 4
    NB: the distribution from arc4random can be very poor, if you happen to choose a poor range. I hadn't realised the powers-of-two expectation. +1 for use @yood's version - made a noticeable difference for larger numbers (e.g. range of 400) – Adam Feb 29 '12 at 17:03
  • Does it generate 32 bit numbers only? – jjxtra Jul 12 '12 at 22:18
  • how does arc4random() 'know' to limit its return values to below the integer on the other side of the modulo operator if it is not being passed into the function? – codecowboy Feb 17 '13 at 08:39
  • 4
    @codecowboy It doesn't. It always returns an integer in the range [0, (2^32)-1]. It's the modulo that limits the upper-bound of the range to the number you specify. – mota Mar 23 '13 at 05:04
  • 1
    Wouldn't this give a random number between 0 and 73? – Tom Howard May 11 '15 at 15:18
  • At some point, the arc4random API changed, as available to Objective C programmers in macOS. Now, `arc4random()` uses default bounds, and `arc4random_uniform(max)` is bounded as you specify. – mcandre Nov 28 '16 at 23:04
429

Use the arc4random_uniform(upper_bound) function to generate a random number within a range. The following will generate a number between 0 and 73 inclusive.

arc4random_uniform(74)

arc4random_uniform(upper_bound) avoids modulo bias as described in the man page:

arc4random_uniform() will return a uniformly distributed random number less than upper_bound. arc4random_uniform() is recommended over constructions like ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.

Community
  • 1
  • 1
yood
  • 6,650
  • 3
  • 26
  • 24
  • 32
    Note that arc4random_uniform() requires iOS 4.3. In case you're supporting older devices, you should add a check: `#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_3` If it fails the check, fall back to another solution. – Ron Jan 20 '12 at 00:39
  • 6
    arc4random_uniform() requires 10.7 or later as well. It crashes your app in 10.6 – Tibidabo Oct 13 '12 at 05:57
  • @Tibidabo Your comment is very false and misleading. I just tired using arc4random_uniform() on iOS 10.3 and there are no problems. It doesn't require 10.7 or later – Fourth Oct 30 '17 at 22:54
  • 1
    @Fourth There is no such thing as iOS 10.7, it is macOS 10.7. It has been more than 5 years since I wrote the comment it was max iOS 5 back then. – Tibidabo Oct 31 '17 at 23:46
65

Same as C, you would do

#include <time.h>
#include <stdlib.h>
...
srand(time(NULL));
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).

James Ko
  • 32,215
  • 30
  • 128
  • 239
  • 45
    -1. You need to seed the random number generator or you will get the same pattern of numbers on each execution. – Alex Reynolds Nov 08 '09 at 22:29
  • How about I want to start from a different number than zero? – amok Jun 15 '10 at 14:37
  • 3
    @amok: You can just add the number that you want to start from to the result – Florin Aug 12 '10 at 08:23
  • 2
    I keep getting the number 9. Pretty random I'd say ;D – alexyorke Aug 30 '10 at 18:07
  • i just tested random(), and it showed the same problem as rand() – LolaRun Feb 24 '12 at 17:42
  • @alexy13, it is "random" in the way that, you didn't know it is 9 before you run it. LOL – Franklin Yu May 15 '16 at 04:56
  • The results of that won't be uniformly distributed unless the largest number rand() gives you is -1 (mod 74). It's unlikely to matter much, but to avoid it you should draw a new random number if rand() happens to fall into that narrow incomplete slice at the end, if you know what I mean. – Fab Aug 15 '17 at 22:05
51

I thought I could add a method I use in many projects.

- (NSInteger)randomValueBetween:(NSInteger)min and:(NSInteger)max {
    return (NSInteger)(min + arc4random_uniform(max - min + 1));
}

If I end up using it in many files I usually declare a macro as

#define RAND_FROM_TO(min, max) (min + arc4random_uniform(max - min + 1))

E.g.

NSInteger myInteger = RAND_FROM_TO(0, 74) // 0, 1, 2,..., 73, 74

Note: Only for iOS 4.3/OS X v10.7 (Lion) and later

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Groot
  • 13,943
  • 6
  • 61
  • 72
  • Addition is commutative, even on fixed with binary integers using twos-complement. As such max - min + 1 is exactly the same as max + 1 - min as well as 1 + max - min. – Michael Morris Apr 09 '14 at 17:11
44

This will give you a floating point number between 0 and 47

float low_bound = 0;      
float high_bound = 47;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

Or just simply

float rndValue = (((float)arc4random()/0x100000000)*47);

Both lower and upper bound can be negative as well. The example code below gives you a random number between -35.76 and +12.09

float low_bound = -35.76;      
float high_bound = 12.09;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

Convert result to a rounder Integer value:

int intRndValue = (int)(rndValue + 0.5);
Tibidabo
  • 21,461
  • 5
  • 90
  • 86
  • This is bad. Why are you using float, and not double? And if your floating point values are from 0 to 47, then (int) (rndValue + 0.5) will convert only values from 0.0 to 0.5 to 0, but values from 0.5 to 1.5 will be converted to 1 etc. So the numbers 0 and 47 will come up only half as often as all the other numbers. – gnasher729 Feb 28 '14 at 23:42
  • @gnasher729 Sorry I don't see your point. Obviously if you need double precision you can easy replace "float" with "double" – Tibidabo Mar 02 '14 at 07:13
  • I don't think it is a big deal. If you need integer only values than you can use arc4random()/0x100000000)*(high_bound-low_bound)+low_bound by removing float/double conversion. – Tibidabo Mar 02 '14 at 07:21
  • You get bias when you convert integer to floating point this way. Use [`drand48`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html) instead for floating points. – Franklin Yu May 15 '16 at 05:00
37

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
  • 4,095
  • 1
  • 26
  • 23
  • 7
    You might as well call srandomdev() instead of passing the time to srandom(); it's just as easy and mathematically better. – benzado Feb 04 '09 at 18:27
31

Better to use arc4random_uniform. However, this isn't available below iOS 4.3. Luckily iOS will bind this symbol at runtime, not at compile time (so don't use the #if preprocessor directive to check if it's available).

The best way to determine if arc4random_uniform is available is to do something like this:

#include <stdlib.h>

int r = 0;
if (arc4random_uniform != NULL)
    r = arc4random_uniform (74);
else
    r = (arc4random() % 74);
AW101
  • 1,620
  • 14
  • 15
  • 9
    This question is about Objective-C which uses late binding. Unlike C which binds at compile/link time, Objective-C binds symbols at runtime, and symbols it cant bind are set to NULL. While you are right that this is not valid C, it most certainly is valid Objective-C. I use this exact code in my iPhone app. [p.s. please can you correct your downvote]. – AW101 Aug 11 '12 at 07:18
  • Whilst objective-c uses late binding for objc methods, for a C function this is not the case. This code will certainly crash if the function doesn't exist at run-time. – Richard J. Ross III Aug 11 '12 at 13:23
  • 8
    According to Apple "...the linker sets the address of unavailable functions to NULL...", See listing 3.2: http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW6. Ok so it has to be weakly linked, but it does not crash. – AW101 Aug 11 '12 at 22:02
  • 1
    Checking that the address of a function is NULL is a method that has been used in all versions of C, C++ and Objective-C both on MacOS X and iOS. – gnasher729 Feb 28 '14 at 23:44
14

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
  • 4,874
  • 6
  • 41
  • 50
  • 3
    1. Random number functions created at random are usually not very random. 2. It is totally broken on a 64 bit processor. 3. Using seconds since 1970 as the random seed makes the numbers predictable. – gnasher729 Feb 28 '14 at 23:48
7

There are some great, articulate answers already, but the question asks for a random number between 0 and 74. Use:

arc4random_uniform(75)

Tom Howard
  • 4,672
  • 2
  • 43
  • 48
4

Generate random number between 0 to 99:

int x = arc4random()%100;

Generate random number between 500 and 1000:

int x = (arc4random()%501) + 500;
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
adijazz91
  • 404
  • 3
  • 12
4

As of iOS 9 and OS X 10.11, you can use the new GameplayKit classes to generate random numbers in a variety of ways.

You have four source types to choose from: a general random source (unnamed, down to the system to choose what it does), linear congruential, ARC4 and Mersenne Twister. These can generate random ints, floats and bools.

At the simplest level, you can generate a random number from the system's built-in random source like this:

NSInteger rand = [[GKRandomSource sharedRandom] nextInt];

That generates a number between -2,147,483,648 and 2,147,483,647. If you want a number between 0 and an upper bound (exclusive) you'd use this:

NSInteger rand6 = [[GKRandomSource sharedRandom] nextIntWithUpperBound:6];

GameplayKit has some convenience constructors built in to work with dice. For example, you can roll a six-sided die like this:

GKRandomDistribution *d6 = [GKRandomDistribution d6];
[d6 nextInt];

Plus you can shape the random distribution by using things like GKShuffledDistribution.

TwoStraws
  • 12,862
  • 3
  • 57
  • 71
  • Mersenne is fastest and best for things like game dev where quality of the random number generated isn't usually too important. – Robert Wasmann Jul 15 '16 at 04:47
2

//The following example is going to generate a number between 0 and 73.

int value;
value = (arc4random() % 74);
NSLog(@"random number: %i ", value);

//In order to generate 1 to 73, do the following:
int value1;
value1 = (arc4random() % 73) + 1;
NSLog(@"random number step 2: %i ", value1);

Output:

  • random number: 72

  • random number step 2: 52

soumya
  • 3,801
  • 9
  • 35
  • 69
1

For game dev use random() to generate randoms. Probably at least 5x faster than using arc4random(). Modulo bias is not an issue, especially for games, when generating randoms using the full range of random(). Be sure to seed first. Call srandomdev() in AppDelegate. Here's some helper functions:

static inline int random_range(int low, int high){ return (random()%(high-low+1))+low;}
static inline CGFloat frandom(){ return (CGFloat)random()/UINT32_C(0x7FFFFFFF);}
static inline CGFloat frandom_range(CGFloat low, CGFloat high){ return (high-low)*frandom()+low;}
Robert Wasmann
  • 897
  • 7
  • 17
  • Be aware though that random() isn't quite so random, so if speed isn't important in your code (like if only used once in a while) then use arc4random(). – Robert Wasmann Jul 18 '16 at 15:39