0

I have a int i generated from( arc4random() % 4), and then I create a new radon int q from another (arc4random() % 4), I wish q is generated until that is different from i.

For example, if i = 2, q must be 0, 1, 3.

How can I do that? Is there a loop or condition can be applied? Thanks

Graphite
  • 346
  • 3
  • 11

5 Answers5

4
int q = (arc4random() % 4);
int i = (arc4random() % 4);
while (q == i) {
  q = (arc4random() % 4);
}
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
Volodymyr B.
  • 3,369
  • 2
  • 30
  • 48
1

Use a while loop and store the previous result.

For example,

int previous = (arc4random() % 4);
int current = (arc4random() % 4);
while(current  == previous)
{
 current = (arc4random() % 4);
}
lakshmen
  • 28,346
  • 66
  • 178
  • 276
1

As some answers here have stated, arc4random with a while loop, in general, is the right answer, but you likely want to use arc4random_uniform(x), as it avoids modulo bias.

From the docs:

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.
greymouser
  • 3,133
  • 19
  • 22
0
int p = (arc4random() % 4);
int q = (arc4random() % 4);
while (p == q) {
  p = (arc4random() % 4);
}
Sport
  • 8,570
  • 6
  • 46
  • 65
0

I have found when I need randomness, it's nice to use a protocol so I can have random number generators of different flavors, yet not have to change any code when I change generators. With this approach, you can easily change the characteristic of your RNG.

If you wanted to prevent duplicates until all numbers have been used, you could substitute with a class that shuffled the values, then provided them until they were gone... shuffled again... etc. Of course, that approach only works if you have a small number of possible values. For much larger values a probabilistic approach would be necessary.

You would have this protocol somewhere...

@protocol RandomNumberGenerator <NSObject>
- (uint32_t)randomNumber;
@end

Then you could have this class, which provides a specific implementation of the protocol...

@interface NonRepeatingRandomNumberGenerator : NSObject<RandomNumberGenerator>
- (instancetype)init;
- (instancetype)initWithUpperBound:(uint32_t)upperBound;
- (uint32_t)randomNumber;
@end

@implementation NonRepeatingRandomNumberGenerator {
    uint32_t lastNumber_;
    uint32_t *upperBound_;
}

- (instancetype)init
{
    if (self = [super init]) {
        lastNumber_ = arc4random();
        upperBound_ = NULL;
    }
    return self;
}

- (instancetype)initWithUpperBound:(uint32_t)upperBound
{
    if (self = [super init]) {
        lastNumber_ = arc4random_uniform(upperBound);
        upperBound_ = malloc(sizeof(*upperBound_));
        *upperBound_ = upperBound;
    }
    return self;
}

- (void)dealloc
{
    free(upperBound_);
}

- (uint32_t)randomNumber
{
    uint32_t result;
    do {
        result = upperBound_ ? arc4random_uniform(*upperBound_) : arc4random();
    } while (result != lastNumber_);
    lastNumber_ = result;
    return result;
}
@end

And then to use, you could make the RNG a property of your class, or make it generally available in some other manner...

self.randomGenerator = [NonRepeatingRandomNumberGenerator initWithUpperBound:4];

Later, wherever you want a random number...

randomNumber = [self.randomGenerator randomNumber];

If you ever decided to change how you wanted the numbers to be generated, you would simply replace the line that creates the RNG.

Jody Hagins
  • 27,943
  • 6
  • 58
  • 87