web-dev-qa-db-fra.com

Générer des nombres aléatoires en Objective-C

Je suis principalement une tête Java et je veux un moyen de générer un nombre pseudo-aléatoire compris entre 0 et 74. Dans Java, j'utiliserais la méthode suivante:

Random.nextInt(74)

Je ne suis pas intéressé par une discussion sur les graines ou le véritable caractère aléatoire, mais simplement sur la manière dont vous accomplissez la même tâche en Objective-C. J'ai parcouru Google et il semble y avoir beaucoup d'informations différentes et contradictoires.

730
rustyshelf

Vous devez utiliser la fonction arc4random_uniform(). Il utilise un algorithme supérieur à Rand. Vous n'avez même pas besoin de mettre une graine.

#include <stdlib.h>
// ...
// ...
int r = arc4random_uniform(74);

La page de manuel arc4random:

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))
1010
lajos

Utilisez la fonction arc4random_uniform(upper_bound) pour générer un nombre aléatoire dans une plage. Ce qui suit va générer un nombre compris entre 0 et 73 inclus.

arc4random_uniform(74)

arc4random_uniform(upper_bound) évite biais modulo comme décrit dans la page de manuel:

arc4random_uniform () retournera un nombre aléatoire uniformément distribué inférieur à upper_bound. arc4random_uniform () est recommandé par rapport à des constructions telles que "arc4random ()% upper_bound", car il évite " modulo partial " lorsque la borne supérieure n'est pas une puissance de deux.

422
yood

Comme C, tu ferais

#include <time.h>
#include <stdlib.h>
...
srand(time(NULL));
int r = Rand() % 74;

(en supposant que vous vouliez dire inclure 0 mais exclure 74, comme dans votre exemple Java]

Edit: N'hésitez pas à remplacer random() ou arc4random() par Rand() (ce qui, comme d'autres l'ont fait remarquer, est plutôt nul).

63
Mike F

Je pensais pouvoir ajouter une méthode que j'utilise dans de nombreux projets.

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

Si je finis par l’utiliser dans de nombreux fichiers, j’ai l'habitude de déclarer une macro

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

Par exemple.

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

Remarque: uniquement pour iOS 4.3/OS X v10.7 (Lion) et ultérieur

47
Groot

Cela vous donnera un virgule flottante nombre compris entre 0 et 47

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

Ou tout simplement

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

Les limites inférieure et supérieure peuvent également être négatif. L'exemple de code ci-dessous vous donne un nombre aléatoire compris entre -35,76 et +12,09.

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

Convertir le résultat en arrondisseur entier valeur:

int intRndValue = (int)(rndValue + 0.5);
44
Tibidabo

Selon la page de manuel de Rand (3), la famille de fonctions Rand est obsolète par random (3). Cela est dû au fait que les 12 bits inférieurs de Rand () passent par un schéma cyclique. Pour obtenir un nombre aléatoire, ensemencez simplement le générateur en appelant srandom () avec une graine non signée, puis appelez random (). Ainsi, l'équivalent du code ci-dessus serait

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

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

Vous aurez seulement besoin d'appeler srandom () une fois dans votre programme, à moins que vous ne vouliez changer votre graine. Bien que vous ayez déclaré ne pas vouloir discuter de valeurs réellement aléatoires, Rand () est un très mauvais générateur de nombres aléatoires et random () souffre toujours du biais modulo, car il génère un nombre compris entre 0 et Rand_MAX. Donc, par exemple Si Rand_MAX est égal à 3 et que vous souhaitez un nombre aléatoire compris entre 0 et 2, vous avez deux fois plus de chances d'obtenir un 0 qu'un 1 ou un 2.

37
Michael Buckley

Mieux vaut utiliser arc4random_uniform. Cependant, ceci n'est pas disponible sous iOS 4.3. Heureusement, iOS liera ce symbole lors de l'exécution, pas lors de la compilation (n'utilisez donc pas la directive #if du préprocesseur pour vérifier sa disponibilité).

Le meilleur moyen de déterminer si arc4random_uniform est disponible est de procéder de la manière suivante:

#include <stdlib.h>

int r = 0;
if (arc4random_uniform != NULL)
    r = arc4random_uniform (74);
else
    r = (arc4random() % 74);
31
AW101

J'ai écrit ma propre classe d'utilitaires de nombres aléatoires simplement pour avoir quelque chose qui fonctionne un peu plus comme Math.random () en Java. Il a juste deux fonctions, et tout est fait en C.

En tête de fichier:

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

Fichier d'implémentation:

//Random.m
static unsigned long seed;

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

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

C'est un moyen assez classique de générer des pseudo-randoms. Dans mon délégué d'applications, j'appelle:

#import "Random.h"

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

Puis plus tard, je dis simplement:

float myRandomNumber = nextRandomFloat() * 74;

Notez que cette méthode renvoie un nombre aléatoire compris entre 0.0f (inclus) et 1.0f (exclusif).

14
Eli

Il existe déjà d’excellentes réponses articulées, mais la question demande un nombre aléatoire compris entre 0 et 74. Utilisez:

arc4random_uniform(75)

7
Tom Howard

Générer un nombre aléatoire compris entre 0 et 99:

int x = arc4random()%100;

Générer un nombre aléatoire entre 500 et 1000:

int x = (arc4random()%501) + 500;
3
adijazz91

À partir de iOS 9 et OS X 10.11, vous pouvez utiliser les nouvelles classes GameplayKit pour générer des nombres aléatoires de différentes manières.

Vous avez le choix entre quatre types de source: une source aléatoire générale (sans nom, au système de choisir ce qu’elle fait), linéaire congruentielle, ARC4 et Mersenne Twister. Ceux-ci peuvent générer des ints, des floats et des bools aléatoires.

Au niveau le plus simple, vous pouvez générer un nombre aléatoire à partir de la source aléatoire intégrée du système, comme suit:

NSInteger Rand = [[GKRandomSource sharedRandom] nextInt];

Cela génère un nombre compris entre -2 147 483 648 et 2 147 483 647. Si vous voulez un nombre compris entre 0 et une limite supérieure (exclusive), vous utiliserez ceci:

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

GameplayKit a des constructeurs de confort intégrés pour fonctionner avec des dés. Par exemple, vous pouvez lancer un dé à six faces comme ceci:

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

De plus, vous pouvez modeler la distribution aléatoire en utilisant des choses comme GKShuffledDistribution.

3
TwoStraws

// L'exemple suivant va générer un nombre compris entre 0 et 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);

Sortie:

  • nombre aléatoire: 72

  • nombre aléatoire étape 2: 52

2
Sujania

Pour les développeurs de jeux, utilisez random () pour générer des randoms. Probablement au moins 5 fois plus rapide que d'utiliser arc4random (). Le biais modulo n’est pas un problème, en particulier pour les jeux, lorsqu’il génère des aléas en utilisant toute la gamme random (). Assurez-vous de semer en premier. Appelez srandomdev () dans AppDelegate. Voici quelques fonctions d'aide:

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;}
1
Robert Wasmann