el3ktro
el3ktro

Reputation: 167

arc4random in NSNumber giving negative values?

I'm creating a random number and storing it in a NSNumber object like this:

NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(2^32-1)];

I also tried:

NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(4294967295)];
NSNumber *index = @(arc4random_uniform(4294967295));

At some point I'm also assigning the number 1 like this:

NSNumber *index = @(1);

This should give me only positive numbers.

Later on, I print out these numbers like this:

NSString *string = [NSString stringWithFormat:@"%@", index];

This gives me some negative values for the random numbers and 1 is being printed as 1. So I though maybe if I do:

NSString *string = [NSString stringWithFormat:@"%u", index.unsignedIntValue];

I'll get only positive numbers - which I do - but now 1 is suddenly being printed as some large positive number, also.

What's going on here? How can I correctly store a u_int32 (which arc4random returns) in a NSNmber and make sure that they are only positive?

Upvotes: 1

Views: 1578

Answers (2)

Martin R
Martin R

Reputation: 539735

You said in a comment that the index is stored in a Core Data entity as an "Integer 32" attribute, and I assume that is where the problem comes from.

Core Data dynamically generates getter and setter methods for all attributes (and relationships) of managed object classes. These accessor methods are different from the "usual" @synthesized accessor methods which are backed up by an instance variable.

For an "Integer 32" attribute, Core Data uses a (signed) integer for the attribute, and when you set a value, it is just cast or truncated to int. Example:

e.index = [NSNumber numberWithUnsignedInt:0xFFFFFFF0U];
// This would give the same result:
// e.index = [NSNumber numberWithLongLong:0x1234FFFFFFF0LL];
NSNumber *val = e.index;
NSLog(@"value=%@, type=%s", val, [val objCType]);
// Output: value=-16, type=i

The output type=i shows that the value contains an int.

If you need unsigned integers in the range 0 .. 2^32-1, then you can either (as you already did) use unsignedIntValue:

unsigned x = [val unsignedIntValue];

or store the attribute as "Integer 64".

Remarks:

  • I am fairly sure that this is not a problem of arc4random_uniform.
  • In your first code example arc4random_uniform(2^32-1), you should note that ^ is exclusive-or, not exponentiation.

Upvotes: 0

Rikkles
Rikkles

Reputation: 3372

Use

NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(exp2(32)-1)];

I never get any negative numbers. arc4random_uniform(x) always returns a number between 0 and x, and the stringvalue of the NSNumber generated from it is correct.

EDIT: replaced exp2(31) with exp2(32)

Upvotes: 0

Related Questions