Although I already found a function SysRandomNumber, I still don't understand how to use it and how it's possible to mimicry exactly the ANSI C srand() maybe using a #define.
I brought up this question with John Hansen over email last year. He wrote back the following:
The standard firmware doesn't expose a way to seed the random number generator used internally by the RandomNumber system call. I haven't ever bothered to expose it in the enhanced NBC/NXC firmware either. Here's the firmware code:
NXT_STATUS cCmdWrapRandomNumber(UBYTE * ArgV[])
{
static UBYTE count = 0;
SWORD random;
if (count == 0)
srand(dTimerRead());
if (count > 20)
count = 0;
else
count++;
//!!! IAR's implementation of the rand() library function returns signed
// values, and we want it that way.
// Some stdlib implementations may return only positive numbers, so be wary
// if this code is ported.
random = rand();
*((SWORD *)ArgV[0]) = random;
return NO_ERR;
}
So this means that every 20 times you call the RandomNumber system call function it will reseed by calling srand and passing in the current firmware timer value (1ms resolution).
You can see from this that srand is being called continually by the firmware, so having it available explicitly won't help much. The rand function in NXC simply doesn't work much like the one in Unix.
Morton,
thx for your reply!
As my English is very poor I actually don't understand the meaning of what you wrote...
so what does this mean
So this means that every 20 times you call the RandomNumber system call function it will reseed by calling srand and passing in the current firmware timer value (1ms resolution).
in simple words related to both
- the srand seed which you need at every new program start (so that you won't get the same series of "random " numbers each time
- and -
- every following rand call
Of course,
a random number (series) is needed in order NOT to have the same series each time in each program run...
so how can I get independend random number series starting with a new seed each time?
I didn't write it. John Hansen wrote it. I am quoting from an email he sent me. The code in the quoted section comes from the NXT firmware. It shows how LEGO implemented the random number generator in the firmware.
I would say that John is telling us (and the quoted code supports this) that there is no use for an exposed srand API call because the firmware is calling srand internally every 20 msec. I think that LEGO did this so the users would not need to remember to call srand themselves. Perhaps LEGO thought it would be too complicated for the younger users to understand how srand and rand interact with each other. That is just a guess, though.
One side effect of this is that it is impossible to use srand to get a repeatable sequence of pseudo-random numbers for testing purposes. This is too bad, but it is something we have to live with if John's firmware is to remain compatible with LEGO's.
ok, thank you!
I know that you partially quoted John's answer in what you wrote ;)
But if I understand you correctly, we will get at least ALWAYS an independent series of random numbers and NEVER identical series....(?)
Another point is - my personal "ceterum censeo" - it is not forbidden to John to make his EFW different AND better than the original one and NXC "Almost Completely Disputably C" ("ACDC") - (maybe using #ifdefines and a "100% compatibility checkbox" in the compiler settings)... :P
thx Andy, I appreciate your idea!
But to be honest, I don't understand how to make that code work for the "whole" srand and rand functionality:
srand(const int variant) for reproducible pseudo random numbers series and
srand( time(NULL) ) for "real independent" random number series
00034 #include <libpayload.h>
00035
00036 static unsigned int next = 1;
00037
00038 int rand_r(unsigned int *seed)
00039 {
00040 *seed = *seed * 1103515245 + 12345;
00041 return (*seed % ((unsigned int)RAND_MAX + 1));
00042 }
00043
00044 int rand(void)
00045 {
00046 return (rand_r(&next));
00047 }
00048
00049 void srand(unsigned int seed)
00050 {
00051 next = seed;
00052 }
CMIIW, but as far as I see you will always get the same series of numbers with your code - but maybe it achieves this nevertheless using those pointer tricks (and here I have no idea how to mimcry this by NXC).
remember, I'm not a programmer, or a IT professional I'm just a simple Lego user ;)
Last edited by HaWe on 29 Jan 2011, 17:47, edited 1 time in total.
if you call srand with a fixed number like say 1 or 27 or 42 you will get a different series of numbers returned from rand for each. But the series will be the same if you use the same seed (the value passed into srand). So to get a different set of numbers each time you run your program you need to get a "random seed" typically these come from things like the system time, or by timing something like the gab between two button presses (or if you are really serious from a white noise source).
yes, I also had the idea to use sth like a "press a btn to start program" loop at the program start, using the timer counter in the loop as a seed for the random function.
But nevertheless I still have no idea how to transcode your example into pointer-less code...