Random number issue in Cocoa

Discussion in 'Mac Programming' started by bahlquist, Oct 15, 2010.

  1. macrumors member

    Joined:
    Oct 6, 2010
    #1
    Hi,
    I made a simple program with a single button, that when pressed gives me a random number. I ran into some issues which several calls of NSLog highlight. Here is my code:

    BARandom.h:

    Code:
    #import <Cocoa/Cocoa.h>
    
    @interface BARandom : NSObject {
       	NSNumber* probability;
    }
    - (IBAction)button:(id)sender;
    @end



    BARandom.m:

    Code:
    #import "BARandom.h"
    #include <math.h>
    
    @implementation BARandom
    - (IBAction)button:(id)sender {
    	NSNumber* theNumb;
    	theNumb=[[NSNumber numberWithFloat:rand()] retain]; 
    	NSLog(@"%d", [theNumb floatValue]);
    	NSLog(@"%d", ([theNumb floatValue]+1));
    	NSLog(@"%d and %d", [theNumb floatValue],[theNumb floatValue]);
    	}
    @end
    In the three calls of NSLog, the second number printed is the same as the first, even though it should be 1 greater. The fourth number is different from the rest. In addition, the first three numbers (being the same) only differ by several hundred or so at each press, where as the fourth differs a lot, is sometimes negative, and often repeats.

    Any ideas on what is going on?
     
  2. macrumors 6502

    Joined:
    Jul 25, 2006
    #2
    %d is for signed integers. For floats, use %f.
     
  3. thread starter macrumors member

    Joined:
    Oct 6, 2010
    #3
    Thanks. I feel stupid. I will probably remember it well now.

    I still am not getting 1 added to the second output. Tried forcing 1 to be a float by writing (float)1 instead.

    I also had trouble when I seeded my random numbers inside the function declaration.
     
  4. macrumors 603

    Joined:
    Aug 9, 2009
    #4
    Post your modified code.

    In general, always post code. Descriptions can differ from code. Also, we can't debug descriptions.
     
  5. thread starter macrumors member

    Joined:
    Oct 6, 2010
    #5
    Change "%d" to "%f" everywhere:

    BARandom.h:

    Code:
    #import <Cocoa/Cocoa.h>
    
    @interface BARandom : NSObject {
       	NSNumber* probability;
    }
    - (IBAction)button:(id)sender;
    @end
    
    

    BARandom.m:

    Code:
    #import "BARandom.h"
    #include <math.h>
    
    @implementation BARandom
    - (IBAction)button:(id)sender {
    	NSNumber* theNumb;
    	theNumb=[[NSNumber numberWithFloat:rand()] retain]; 
    	NSLog(@"%f", [theNumb floatValue]);
    	NSLog(@"%f", ([theNumb floatValue]+1));
    	NSLog(@"%f and %f", [theNumb floatValue],[theNumb floatValue]);
    	}
    @end
    
    Second number in output is not 1 greater than the first.
     
  6. thread starter macrumors member

    Joined:
    Oct 6, 2010
    #6
    Concerning the random number seeding: seeding inside the function declaration as follows was a problem:

    BARandom.h:

    Code:
    #import <Cocoa/Cocoa.h>
    
    @interface BARandom : NSObject {
       	NSNumber* probability;
    }
    - (IBAction)button:(id)sender;
    @end



    BARandom.m:

    Code:
    #import "BARandom.h"
    #include <math.h>
    
    @implementation BARandom
    - (IBAction)button:(id)sender {
            srand(time(0));
    	NSNumber* theNumb;
    	theNumb=[[NSNumber numberWithFloat:rand()] retain]; 
    	NSLog(@"%d", [theNumb floatValue]);
    	NSLog(@"%d", ([theNumb floatValue]+1));
    	NSLog(@"%d and %d", [theNumb floatValue],[theNumb floatValue]);
    	}
    @end
    
    The output numbers were very close to one another. I fixed this problem by moving the "srand(time(0))" line to the "main()" function. Not sure why it didn't work when called as above.
     
  7. macrumors 603

    Joined:
    Aug 9, 2009
    #7
    It didn't work because you were reseeding every time. You were also reseeding with the current time. Since the time advances linearly, you were reseeding with a series of numbers that were very close to one another. Frequent reseeding is never good, but frequent reseeding with non-random values can utterly destroy the randomness of any generator.

    I also recommend reading the man page for rand() and srand(), especially this summary at the top of the page:
    rand, srand, sranddev, rand_r -- bad random number generator
    So another contributing factor is that the functions you're using are a bad random number generator. The random() or arc4random() functions are much better, as noted in the man page for rand().

    And your posted code is again using %d when it should be using %f, so it's wrong again.
     
  8. thread starter macrumors member

    Joined:
    Oct 6, 2010
    #8
    Thanks. I knew that time was a factor here, but I thought the seeded values, if slightly different, would lead to much different number generations (sensitivity to initial conditions). I guess that's not the case at all and it shows that rand() is not a good random number generator.
     
  9. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #9
    Be aware, again, that you are leaking theNumb each time you call the method. You should either release it at the end of the method or just not retain it in the first place (a method can almost always rely on an autoreleased object for the length of its run, barring the explicit use of an autorelease pool).

    For most math, though, you should probably consider using primitives in place of NSNumber. NSNumber's primary function is as a wrapper for placing numeric values into collections (NSArrays, NSDictionaries, user defaults etc) or perhaps for encoding purposes. Primitives work just fine as local variables as well as ivars and are much faster and easier to work with than NSNumbers.
     
  10. macrumors 603

    Joined:
    Aug 9, 2009
    #10
    Yes it is. Sample output:
    Code:
    2010-10-16 11:34:34.722 a.out[5701] 16807.000000  [COLOR="Red"]<-- first number[/COLOR]
    2010-10-16 11:34:34.722 a.out[5701] 16808.000000  [COLOR="Red"]<-- second number[/COLOR]
    2010-10-16 11:34:34.722 a.out[5701] 16807.000000 and 16807.000000
    
    When you perceive a problem in a program's output, post the output. Be prepared to explain why the output has a problem.

    When describing a problem, always do the following:
    1. Describe exactly what you expected to happen.
    2. Describe exactly what did happen.


    If you meant "the 4th number isn't 1 greater than the 3rd", then you're right, but it's not supposed to be. Your code is this:
    Code:
    	NSLog(@"%d and %d", [theNumb floatValue],[theNumb floatValue]);
    That code prints the same value twice, which is exactly what the sample output shows.

    If you expected that the previous line of code involving a +1 would increment theNumb's floatValue, then that is very badly mistaken.

    So please describe exactly what you expected in the output, and explain why you expected it, and why the sample output is wrong. If you have different output, then post it, because we can't see your screen.
     
  11. thread starter macrumors member

    Joined:
    Oct 6, 2010
    #11
    I'm not sure where the "a" came from in your output. It seems you were using different code since there is no "a" in the code I posted. I will start a new thread on this issue when I have a chance and I will post my code and output from several trials.
     
  12. macrumors 603

    Joined:
    Aug 9, 2009
    #12
    "a.out" is the name of the executable. It's called a.out because I'm lazy when compiling one-off programs at the command-line. a.out is the default name of the compiler's output.

    Look at the output you posted:
    Code:
    [COLOR="Blue"]2010-10-16 18:32:42.181[/COLOR] [COLOR="red"]Tester[/COLOR][COLOR="Green"][419:10b[/COLOR]] 16807.000000 and 16808.000000
    
    Compare to the output I posted:
    Code:
    [COLOR="blue"]2010-10-16 11:34:34.722[/COLOR] [COLOR="Red"]a.out[/COLOR][COLOR="green"][5701][/COLOR] 16807.000000
    
    I've hilited the corresponding parts of each output using the same color. It's possible to infer from the different formats of the green bracketed parts that you're running a GUI Cocoa program, and I'm running a GUI-less program. It should also be obvious that I ran the code you posted earlier, and you ran different code posted later.
     

Share This Page