C++ Question Generating "random" numbers

garyw

O-F Administrator
Administrator
Moderator
Addon Developer
Tutorial Publisher
Joined
May 14, 2008
Messages
10,485
Reaction score
209
Points
138
Location
Kent
Website
blog.gdwnet.com
A friend of mine (ex programmer type) just made a suggestion - Generate your random number using the MJD as a seed. As the MJD is always changing in theory your resulting numbers should have some more randomness to them.
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
A friend of mine (ex programmer type) just made a suggestion - Generate your random number using the MJD as a seed. As the MJD is always changing in theory your resulting numbers should have some more randomness to them.
We're back to the beginning of the topic. Seed the random number generator with the current time (normally and easiest with just the time() function - using MJD will have the same effect but is overkill and does not provide you with anything more random):
Code:
srand(time(NULL));
time() returns the number of seconds since epoch, so you don't need to worry about running it at the same time the next day. Only seed the random number generator once in your code (otherwise it defeats the point of pseudo-random number generation)

rand() is a good-enough-for-most random number generator. If you're not getting random numbers from it then you're using it incorrectly. If you want a random integers in the range a-b, then use:
Code:
int random = a + rand() % (b - a + 1);

rand() is good enough for most uses. If you do not know whether it is good enough for you then either:

  1. It is good enough for you
  2. You do not know your subject matter well enough.
Don't worry about using other methods of random number generation unless you thoroughly understand statistics and know that you need a better random number generator (basically, unless you are doing crypto).
 

RisingFury

OBSP developer
Addon Developer
Joined
Aug 15, 2008
Messages
6,427
Reaction score
492
Points
173
Location
Among bits and Bytes...
A friend of mine (ex programmer type) just made a suggestion - Generate your random number using the MJD as a seed. As the MJD is always changing in theory your resulting numbers should have some more randomness to them.


There's also a function that returns the time your computer has been running in milliseconds. That's also a good seed.
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
Edit : and using what follows, I always get "38" ! What a randomness !

srand((unsigned)time(0));
int lowest=1, highest=100;
int range=(highest-lowest)+1;
int r = lowest+int(range*rand()/(RAND_MAX + 1.0));
As an explanation, here is what is going on. The first 3 lines are fairly simple:
Code:
<seed the randomness>
lowest=1
highest = 100
range = 99
The last one is messy. I've added some extra braces to help you understand the order of precedence:
Code:
int r = lowest+int([B]([/B]range*rand()[B])[/B]/(RAND_MAX + 1.0));
So Let's start putting in some numbers (I'm working on a 64-bit system, so YMMV).
Code:
int r = 1 + int([COLOR=Red][B]([/B][/COLOR]99*rand()[COLOR=Red][B])[/B][/COLOR]/(2147483647 + 1.0));
The important thing to notice here is that rand() returns an int (which is in the range 0 - RAND_MAX (inclusive). It is then multiplied by 99. However, 99 is also an int and one int multiplied by an int returns another int. In this situation, you can get rollover, where the 8-byte integer runs out of space to store it and just wraps around. So in C code (when dealing with 64-bit ints), 2147483647 + 1 = -2147483648. So that means that (99 * rand()) will always be in the range (-2147483648, 2147483647)

Now with the denominator, we have 2147483647 + 1.0. The first number in an int, the second is a float. So what happens is that the int gets cast to a float and then the two added, resulting in (on my compiler) 2147483648.000000. So now we have:
Code:
int r = 1 + int([B]([/B][I]R[/I][B])[/B]/(2147483648.0));
R is in the range -2147483648 ≤ R ≤ 2147483647.
Then the division is performed resulting in:
Code:
int r = 1 + int([I]S[/I]);
Where S is in the range -1 ≤ S < 1. Then you cast it to an int, where it all gets squashed to 0 (apart from the really rare exception where R = -2147483648):

Code:
int r = 1 + 0;
r is (pretty much always) 1. I don't know why you got 38, but this will explain why you weren't getting your expected range.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
If you need true randomness use /dev/random device in linux which works the best (i.e. much faster) when used with [ame="http://en.wikipedia.org/wiki/Hardware_random_number_generator"]Hardware random number generator[/ame], or if don't have one and there is no RNG on the motherboard either, a daemon that gets entropy form FSB/clock drift or a microphone (or a webcam). Otherwise the entropy pool fills very slowly (a bit faster if you type and move mouse randomly :p).
 

Hielor

Defender of Truth
Donator
Beta Tester
Joined
May 30, 2008
Messages
5,580
Reaction score
2
Points
0
There's also a function that returns the time your computer has been running in milliseconds. That's also a good seed.
Not as good as the time in milliseconds since 1970--uptime will repeat, time since 1970 doesn't.
 

boyan3001

New member
Joined
Jul 6, 2011
Messages
13
Reaction score
0
Points
0
Location
Belgrade
Excuse me, I am new in here, but...
You could also use the fact that C++ alow you to define varibale without initializing it. In fact, every time you run your compiled code, that variable will be placed on some pice of memory that already contain some value, lefted behind from a previous user (of memory location).
So define some int seed, do not initialize it, and give that to rand() as seed. This could provide some good randomnes for seeding... but it could be someway predictable.
 

kuddel

Donator
Donator
Joined
Apr 1, 2008
Messages
2,064
Reaction score
507
Points
113
Excuse me, I am new in here, but...
You could also use the fact that C++ alow you to define varibale without initializing it. In fact, every time you run your compiled code, that variable will be placed on some pice of memory that already contain some value, lefted behind from a previous user (of memory location).
So define some int seed, do not initialize it, and give that to rand() as seed. This could provide some good randomnes for seeding... but it could be someway predictable.

This is one (not the best) soluton, but remember that most compilers create different (assemby-)code in DEBUG version versus RELEASE version.
In the DEBUG version uninitialized members/variables are often 'initialized' with a certain pattern (e.g. 0xACACAC, or even 0x00).
This will lead to bad debugging behaviours.

In general:
1) Use rand()/seed() only if you know how it works ;)
2) call seed() only once with a "random" value (time since Epoch is quite OK for that)
3) after that you should only call rand() further on...
simple is that.

/Kuddel
 

n72.75

Move slow and try not to break too much.
Orbiter Contributor
Addon Developer
Tutorial Publisher
Donator
Joined
Mar 21, 2008
Messages
2,696
Reaction score
1,353
Points
128
Location
Saco, ME
Website
mwhume.space
Preferred Pronouns
he/him

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk

A very fine specimen indeed. How did you come by it?

However, it pales compared to my own champion: 470301. This seed will father a sequence so random that even a lump of decaying uranium will tick with the regularity of an atomic clock by comparison.
 

jangofett287

Heat shield 'tester'
Joined
Oct 14, 2010
Messages
1,150
Reaction score
13
Points
53
Excuse me, I am new in here, but...
You could also use the fact that C++ alow you to define varibale without initializing it. In fact, every time you run your compiled code, that variable will be placed on some pice of memory that already contain some value, lefted behind from a previous user (of memory location).
So define some int seed, do not initialize it, and give that to rand() as seed. This could provide some good randomnes for seeding... but it could be someway predictable.

This is risking all sorts of memory leaks just to increase unpredictability, besides, if you only run well written programs that clean up after themselves, this will always turn out as 0 or NULL, depending on the system. I suspect the compiler will also want to chew your head off...
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
You obviously have no idea of how computer programs work.
This is risking all sorts of memory leaks just to increase unpredictability
No it won't. Memory will not leak as you have defined your 4 (or 8) bytes of int on the stack and will get dealt with exactly the same whether it gets initialised or not. Memory won't randomly leak just because you don't initialise one value.

besides, if you only run well written programs that clean up after themselves, this will always turn out as 0 or NULL, depending on the system.
No it won't. Firstly, you can't guarantee that whatever memory the OS assigns to you has been used before, so you can end up with whatever value got assigned to that area when the computer powered on (unless something wrote to it). Furthermore, well written programs that 'clean up' after themselves do things like release resources (including memory). They do not wipe the memory as there is no point as it is not going to be used (by them) again. If I saw code that reset all memory used to a known value when it deallocated it, I would smack the author of it for wasting my time.

I suspect the compiler will also want to chew your head off...
It will likely do one of the following:

  1. Give you a warning you are using an uninitialised value
  2. Give you an error that you are using an uninitualised value (though I have not seen this on C/C++ compilers unless you have the werror flag)
  3. Initialise it for you to 0 or some recognisable pattern
  4. Do nothing.


---------- Post added at 16:40 ---------- Previous post was at 16:29 ----------

This thread now seems to be populated by people who don't understand programming, so I will re-iterate what has already been said by Kuddel/martins/orb:

srand(time(null)); // ONCE ONLY
int r = rand(); // every time you want a random number.

Use these unless you can mathematically prove for your situation why they are insufficient. Otherwise shut up with stupid new ideas to improve randomness. rand() is good enough when used correctly for almost all situations (and I cannot think of any in orbiter where it is not)
 
Last edited by a moderator:

RisingFury

OBSP developer
Addon Developer
Joined
Aug 15, 2008
Messages
6,427
Reaction score
492
Points
173
Location
Among bits and Bytes...
Not as good as the time in milliseconds since 1970--uptime will repeat, time since 1970 doesn't.


I had a similar similar problem when programming for Arduino. Time since Arduino got turned on in milliseconds and microseconds is logged, but the problem is that it can overflow the variable it's stored in. The millisecond counter overflows in 70 days or something, but microsecond counter overflows in a few hours.

How does the PC deal with that? Milliseconds since 1970 is a large number...
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
How does the PC deal with that? Milliseconds since 1970 is a large number...
The format is extended to use wider data variable. For 32-bit time there was [ame="http://en.wikipedia.org/wiki/Year_2038_problem"]Year 2038 problem[/ame], but currently new systems use 64-bit time.
 

Radu094

Donator
Donator
Beta Tester
Joined
Sep 5, 2008
Messages
36
Reaction score
0
Points
6
This could be overkill but I've been using Newran in my work for quite some time.

As others have pointed out before, it's not the "randomness" that's the useful part here, but the various distributions it allows you to generate. This allows you to bind these random numbers directly to a real-life modelling situation (Mean Time Between Failures in your case) without bothering with much of the math detail.
 
Top