how to return rand()'s seed portably?

L

luserXtrog

Hello all.
I'm down to the very last math operator for my postscript interpreter,
and it's a doozy.

Postscript defines three operators related to pseudorandom number
generation:
[args] operator [value(s) returned]
-- rand int
int srand --
-- rrand int

I've got rand and srand using the eponymous standard library
functions:

void Orand() {
push(integer(rand()));
}

void Osrand() {
stackis1(integer,srand); /*assert stack content*/
srand((unsigned)pop.u.i); /*pop,offset,cast,call*/
}

But there's no standard library function to discover the current
state. My man page describes a POSIX function,
int rand_r(unsigned int *seedp);
that would let me maintain the seed in a global or something; but it
also gives an example implementation:

static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned seed) {
next = seed;
}

What's better: steal the code or depend on POSIX?
tia.
 
B

Barry Schwarz

Hello all.
I'm down to the very last math operator for my postscript interpreter,
and it's a doozy.

Postscript defines three operators related to pseudorandom number
generation:
[args] operator [value(s) returned]
-- rand int
int srand --
-- rrand int

Your explanation below is not clear to me. Does rrand return the
current seed? If so, why not let srand save it for you and then rrand
can examine this saved value.
I've got rand and srand using the eponymous standard library
functions:

void Orand() {
push(integer(rand()));
}

void Osrand() {
stackis1(integer,srand); /*assert stack content*/
srand((unsigned)pop.u.i); /*pop,offset,cast,call*/
}

But there's no standard library function to discover the current
state. My man page describes a POSIX function,
int rand_r(unsigned int *seedp);
that would let me maintain the seed in a global or something; but it
also gives an example implementation:

What implies that you need a global.
static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned seed) {
next = seed;
}

What does any of this have to do with rrand?
What's better: steal the code or depend on POSIX?

You tell us. Will anyone ever use your code on a non-POSIX system?
 
L

luserXtrog

Hello all.
I'm down to the very last math operator for my postscript interpreter,
and it's a doozy.
Postscript defines three operators related to pseudorandom number
generation:
[args] operator [value(s) returned]
-- rand int
int srand --
-- rrand int

Your explanation below is not clear to me. Does rrand return the
current seed? If so, why not let srand save it for you and then rrand
can examine this saved value.

Ah, yes. It would perhaps help to mention what it needs to do.
Critical oversight.

From the Postscript manual:
rrand
returns an integer representing the current state of the random number
generator used by rand. This may later be presented as an operand to
srand to reset the random number generator to the current position in
the sequence of numbers produced.

So this program,
5 srand rrand =
should print 5 but this one,
5 srand rand pop rrand =
should print something else.
What implies that you need a global.

Not necessarily a bare global integer just floating off by itself. It
could be in a user-job struct; but it can't be automatic or static or
how could 3 functions access it?
What does any of this have to do with rrand?

It exposes the state variable, the seed, which rrand must retrieve.
You tell us. Will anyone ever use your code on a non-POSIX system?

One can but hope; and endeavour not to erect unnecessary obstacles.

It will require an X-Server for rendering; that seems to require
POSIX. But I was also reluctant to use rand_r because the manpage
doesn't really explain what it does. My first impression upon seeing a
trio of functions where I needed a trio of operators, was dashed by
the realization that rand_r must be the 're-entrant' rand, supplanting
the other two and retaining the seed. But one hestitates to rely on
guesswork. And it seems silly to adopt a supplementary standard just
for one function.
 
L

lawrence.jones

blargg said:
Agreed; why do you feel you need to use a standard random function at all?
Just implement one which satisfies Postscript's requirements.

This is good advice, particularly since Postscript's requirements are
different than C's. In particular, PS rand must return an integer
between 0 and 2**31 - 1 whereas C only requires a range of 0 to
RAND_MAX, which need not be any larger than 2**15 - 1. PS also requires
the entire state of the generator to fit into an integer, which means
that there is only a single sequence of random numbers and the seed just
picks where in the sequence to start. The C specification allows
(although doesn't require) there to be as many possible sequences as
seed values.
reading the man page for rand_r, it does exactly what you want; all of its
state is stored in the integer you pass a pointer to, so you can save and
restore its position.

But note that rand_r has been declared obsolescent and may be removed in
the future.
 
C

CBFalconer

pete said:
luserXtrog wrote:
.... snip ...


Steal the POSIX. That makes it become portable c code.
Then, other people can duplicate your results
with your program, with their c implementations.

No, it makes the code portable to POSIX. If you want portable,
read the C standard and act accordingly.
 
J

jameskuyper

CBFalconer said:
No, it makes the code portable to POSIX. If you want portable,
read the C standard and act accordingly.

To provide context, remember that the code he was asking about
"stealing" was:

static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned seed) {
next = seed;
}

Obviously, he should provide a macro named MY_RAND_MAX to avoid
conflict with the C standard library macro.
What exactly would prevent this code from being ported to a non-POSIX
system?
 
C

CBFalconer

pete said:
CBFalconer wrote:
.... snip ...


You are absolutely wrong, for the reason that you quoted.

I think we are talking about different things. I was talking about
stealing code that used POSIX calls. I think you are talking about
copying that source code, and not using anything that is POSIX
limited.
 
L

luserXtrog

This is good advice, particularly since Postscript's requirements are
different than C's.  In particular, PS rand must return an integer
between 0 and 2**31 - 1 whereas C only requires a range of 0 to
RAND_MAX, which need not be any larger than 2**15 - 1.

Thanks. That's the first thing I should've noticed.

 PS also requires
the entire state of the generator to fit into an integer, which means
that there is only a single sequence of random numbers and the seed just
picks where in the sequence to start.  The C specification allows
(although doesn't require) there to be as many possible sequences as
seed values.


But note that rand_r has been declared obsolescent and may be removed in
the future.

Argv! foiled again. But I think that's good enough for the "make it
work" pass. I'll have to do some reading before the "make it right"
pass.
 
L

luserXtrog

... snip ...



I think we are talking about different things.  I was talking about
stealing code that used POSIX calls.  I think you are talking about
copying that source code, and not using anything that is POSIX
limited.

Even with encrypted questions, you guys never cease to be helpful
(except when being entertaining, of course). I think eventually I
will need to use POSIX for threads, but I was hoping to keep to
standard C (and lean as heavily on the libraries as practical).

It appears the code will only do what I want iff long and int are
both 32 bits. I suppose some more homework on my part is in order.

Thanks to all.
 
L

luserXtrog

I use mostly use two different 32 bit prng's:
     LU_RAND() and LUS_RAND().
They are implemented as macros.
<snipped very nice macros and commentary>

I suspect I'll have to resort to something more like the bad one to
keep the state in one int. What if it was based on a binary
enumeration in the sequence from the I Ching? Or it could interpret
the whole int as octal digits and transform each pair (6 bits) to the
next hexagram.
 
J

James Kuyper

CBFalconer said:
I think we are talking about different things. I was talking about
stealing code that used POSIX calls.

That's not what the OP was talking about.
... I think you are talking about
copying that source code, and not using anything that is POSIX
limited.

Because that is what the OP was talking about. He provided the code he
was talking about "stealing" in his very first message, and it doesn't
contain a single call to a POSIX function. It is the body of a
self-contained POSIX function, with identifiers renamed to prevent
collision with the original. I realize that you have limitations which
prevent you from looking at that message, so you'll just have to take my
word for it.
 
J

James Kuyper

luserXtrog wrote:
....
It appears the code will only do what I want iff long and int are
both 32 bits. ...

The code you posted requires only that ULONG_MAX >= 1103515245, though I
suspect that getting the desired statistical properties requires that
long be at least 32 bits and that int be at least 16 bits. All of this
is guaranteed by the C standard, so there's no need to worry about it.
 
C

CBFalconer

luserXtrog said:
.... snip ...

It appears the code will only do what I want iff long and int are
both 32 bits. I suppose some more homework on my part is in order.

long is guaranteed to be at least 32 bits. int is not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top