Topic: Defect report: inconsistencies in the definitions of rand() and random_shuffle()


Author: kanze@gabi-soft.de (James Kanze)
Date: Sat, 11 Jan 2003 17:25:34 +0000 (UTC)
Raw View
kuyper@wizard.net ("James Kuyper Jr.") wrote in message
news:<3E1D6DD6.6030603@wizard.net>...
> Pete Becker wrote:
> > Tom Hyer wrote:
>  ....
> >>The aim is that users who do not care about the state can easily
> >>ignore it.

> > No. You must know about srand in order to use rand correctly.

> It's quite possible to accidentally use rand() correctly without that
> knowledge. There are contexts where srand() is not needed, and a
> programmer would not be penalized by his ignorance of srand() if he
> happened to be writing code for one of those contexts.

And how is the programmer supposed to know if he is writing code for one
of those contexts or not, if he doesn't know of srand, and its
interaction with rand?

I agree with Pete on this one: rand and srand form a pair, and to use
either rationally, you have to know both.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: thomas.hyer@ubsw.com (Tom Hyer)
Date: Wed, 8 Jan 2003 20:33:42 +0000 (UTC)
Raw View
petebecker@acm.org (Pete Becker) wrote in message news:<3E1B2BF8.1B4DD7C7@acm.org>...
> Tom Hyer wrote:
> >
> >     All these problems stem from the fact that the definition of
> > rand() -- a function requiring no arguments -- is based on the
> > pretense that random generation does not require state.
>
> That's just not true. srand initializes the random number generator's
> state. It couldn't do that if rand didn't require state.
>

That's why I called it a pretense.  Let's go through this again.

"the definition of rand() -- a function requiring no arguments"

means that rand is defined as a function requiring no arguments.  In
other words, the existence of the underlying state is not manifest.
The aim is that users who do not care about the state can easily
ignore it.  This is what I have called "the pretense that random
generation does not require state".

Obviously srand initializes some state which rand sees (and changes).
But you can use rand without ever learning about srand.  The fact that
these functions are so loosely coupled (in the interface) is part of
the defect.

-- Tom Hyer

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Mon, 6 Jan 2003 18:52:57 +0000 (UTC)
Raw View
llewelly.@@xmission.dot.com (llewelly) wrote in message
news:<863co8rbq2.fsf@Zorthluthik.foo>...
> kanze@gabi-soft.de (James Kanze) writes:

> > In '26.5 [lib.c.math], the C++ standard refers to the C standard for
> > the definition of rand(); in the C standard, it is written that "The
> > implementation shall behave as if no library function calls the rand
> > function."

> > In '25.2.11 [lib.alg.random.shuffle], there is no specification as
> > to how the two parameter version of the function generates its
> > random value. I believe that all current implementations in fact
> > call rand()

> all? Why do you believe 'all'?

Frankly, because one person mentionned one implementation which did, and
since most (or all?) implementations derive from a common source...

> I ask because as nearly as I can determine, gcc 3.2.1 and 2.95.3, on
> freebsd and linux, call lrand48, not rand. (However gcc *does* call
> rand on platforms without lrand48.) (Also - one could argue that if
> random_shuffle calls lrand48, the utility of lrand48 is reduced.)
> Since 2.95.3 used a (nearly) unaltered sgi stl, I suspect plenty of
> other implementations do likewise.

There are two problems with such an implementation.  The first, you have
already mentioned: lrand48 is not available on many platforms.

The second is more subtle: for random_shuffle to be really useful, it is
necessary for the user to be able to seed the randomness somehow. On my
system (Solaris 2.8), for example, the documentation for lrand48 says
that "Functions srand48(), seed48(), and lcong48() are initialization
entry points, one of which should be invoked before either drand48(),
lrand48(), or mrand48() is called." Taken literally (and I don't know
how else to take it, if random_shuffle is invoked and I haven't seeded
the random generator, I have undefined behavior.  Strictly speaking, I
don't think that this is conformant -- I have to call a system specific
function before using a function in <algorithm>?

(I'm not trying to critize them for having realized the weaknesses of
rand(), and trying to do better.  But I think we still have a problem
here in the standard.)

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: thomas.hyer@ubsw.com (Tom Hyer)
Date: Tue, 7 Jan 2003 18:53:14 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) wrote in message news:<d6651fb6.0301060504.4a3d6e60@posting.google.com>...
> ... for random_shuffle to be really useful, it is
> necessary for the user to be able to seed the randomness somehow. On my
> system (Solaris 2.8), for example, the documentation for lrand48 says
> that "Functions srand48(), seed48(), and lcong48() are initialization
> entry points, one of which should be invoked before either drand48(),
> lrand48(), or mrand48() is called." Taken literally (and I don't know
> how else to take it, if random_shuffle is invoked and I haven't seeded
> the random generator, I have undefined behavior.  Strictly speaking, I
> don't think that this is conformant -- I have to call a system specific
> function before using a function in <algorithm>?
>
> (I'm not trying to critize them for having realized the weaknesses of
> rand(), and trying to do better.  But I think we still have a problem
> here in the standard.)

    All these problems stem from the fact that the definition of
rand() -- a function requiring no arguments -- is based on the
pretense that random generation does not require state.

    I believe that, as far as possible, we should try to get
rand(void) out of the standard.  I know we can't remove it outright...

    Suppose the standard required an implementation to provide a class
rand_t with:
1)  a default constructor
2)  a constructor from an integer type (to seed)
3)  a static int member rand_max
4)  an operator()(void) which would produce a (pseudo-) random integer
in the range [0, rand_max).

    Then rand() could be implemented using a static rand_t, and
RAND_MAX could be defined as rand_t::rand_max.  This would make the
state requirement explicit and improve thread safety as well.

-- Tom Hyer

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: llewelly.@@xmission.dot.com (llewelly)
Date: Tue, 7 Jan 2003 22:08:40 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

> llewelly.@@xmission.dot.com (llewelly) wrote in message
> news:<863co8rbq2.fsf@Zorthluthik.foo>...
[snip]
> > I ask because as nearly as I can determine, gcc 3.2.1 and 2.95.3, on
> > freebsd and linux, call lrand48, not rand. (However gcc *does* call
> > rand on platforms without lrand48.) (Also - one could argue that if
> > random_shuffle calls lrand48, the utility of lrand48 is reduced.)
> > Since 2.95.3 used a (nearly) unaltered sgi stl, I suspect plenty of
> > other implementations do likewise.
>
> There are two problems with such an implementation.  The first, you have
> already mentioned: lrand48 is not available on many platforms.
>
> The second is more subtle: for random_shuffle to be really useful, it is
> necessary for the user to be able to seed the randomness somehow.

Yes, you said this in your first post. I didn't intend to imply that
    the lack of seed function for random_shuffle was not a problem; I
    was merely nitpicking your use of the word 'all'.

> On my
> system (Solaris 2.8), for example, the documentation for lrand48 says
> that "Functions srand48(), seed48(), and lcong48() are initialization
> entry points, one of which should be invoked before either drand48(),
> lrand48(), or mrand48() is called." Taken literally (and I don't know
> how else to take it, if random_shuffle is invoked and I haven't seeded
> the random generator, I have undefined behavior.  Strictly speaking, I
> don't think that this is conformant -- I have to call a system specific
> function before using a function in <algorithm>?
[snip]

Possibly it isn't. I can't tell.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: 04 Jan 03 14:50:21 GMT
Raw View
In '26.5 [lib.c.math], the C++ standard refers to the C standard for the
definition of rand(); in the C standard, it is written that "The
implementation shall behave as if no library function calls the rand
function."

In '25.2.11 [lib.alg.random.shuffle], there is no specification as to
how the two parameter version of the function generates its random
value.  I believe that all current implementations in fact call rand()
(in contradiction with the requirement avove); if an implementation does
not call rand(), there is the question of how whatever random generator
it does use is seeded.  Something is missing.

I would suggest the following changes:

In [lib.c.math], add a paragraph specifying that the C definition of
rand shal be modified to say that "Unless otherwise specified, the
implementation shall behave as if no library function calls the rand
function."

In [lib.alg.random.shuffle], add a sentence to the effect that "The two
argument form of the function is the equivalent of calling the three
parameter form with the function rand [lib.c.math] as the third
parameter.  [Note: if the number of elements in the sequence is larger
than RAND_MAX, this may result in a less than random shuffling.]"

Formally speaking, the note is probably not necessary, but it does make
it clear that we were aware of the limitation, decided that it wasn't
worth doing anything else about it, and that's life -- if you have more
elements, it's your problem.  (There are some good solutions to this in
boost, but it's not yet appropriate to mention them in the standard.)

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orientie objet/
                    Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]




Author: llewelly.@@xmission.dot.com (llewelly)
Date: Sat, 4 Jan 2003 20:04:59 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

F> In '26.5 [lib.c.math], the C++ standard refers to the C standard for the
> definition of rand(); in the C standard, it is written that "The
> implementation shall behave as if no library function calls the rand
> function."
>
> In '25.2.11 [lib.alg.random.shuffle], there is no specification as to
> how the two parameter version of the function generates its random
> value.  I believe that all current implementations in fact call
> rand()

all? Why do you believe 'all'? I ask because as nearly as I can
    determine, gcc 3.2.1 and 2.95.3, on freebsd and linux, call
    lrand48, not rand. (However gcc *does* call rand on platforms
    without lrand48.) (Also - one could argue that if random_shuffle
    calls lrand48, the utility of lrand48 is reduced.) Since 2.95.3
    used a (nearly) unaltered sgi stl, I suspect plenty of other
    implementations do likewise.

A short test:

#include<cstdlib>
#include<algorithm>
#include<iostream>

using std::rand; using std::srand;
using std::random_shuffle;
using std::cout; using std::endl;

int main()
  {
    int foo[10]= {0,1,2,3,4,5,6,7,8,9};
    cout << "rand starting with seed 1:" << endl;
    srand(1);
    for (int i= 0; i < 10 ; ++i)
    {
      cout << "rand call number " << i << " returns " << rand() << endl;
    }
    cout << "Reseeding rand with srand(1)." << endl;
    srand(1);
    for (int i= 0; i < 10 ; ++i)
    {
      cout << "rand call number " << i << " returns " << rand() << endl;
      cout << "Calling random shuffle." << endl;
      random_shuffle(foo,foo+10);
    }
  }


> (in contradiction with the requirement avove); if an implementation does
> not call rand(), there is the question of how whatever random generator
> it does use is seeded.  Something is missing.
[snip]

Of course the missing specification of how the random generator is
    seeded is still a problem.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: chrisnewton@no.junk.please.btinternet.com ("Chris Newton")
Date: Sun, 5 Jan 2003 05:36:39 +0000 (UTC)
Raw View
"James Kanze" <kanze@gabi-soft.de> wrote...
> In '26.5 [lib.c.math], the C++ standard refers to the
> C standard for the definition of rand(); in the C standard,
> it is written that "The implementation shall behave as if
> no library function calls the rand function."
>
> In '25.2.11 [lib.alg.random.shuffle], there is no
> specification as to how the two parameter version of the
> function generates its random value.  I believe that all
> current implementations in fact call rand() (in
> contradiction with the requirement avove); if an
> implementation does not call rand(), there is the question
> of how whatever random generator it does use is seeded.
> Something is missing.

I don't think all current implementations call rand(), though certainly
some do. IIRC, at least a couple use internal functions, which may also
be used by rand() independently and without side effects.

As you say, there is also the question of seeding; does srand() seed
random_shuffle(), and if not, what does? Even where random_shuffle() is
not implemented in terms of rand(), every implementation I've looked
into used srand() to set the seed for the shuffle function.

Regards,
Chris


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hinnant@metrowerks.com (Howard Hinnant)
Date: Sun, 5 Jan 2003 07:43:32 +0000 (UTC)
Raw View
In article <d6651fb6.0301030529.49c0a54@posting.google.com>, James
Kanze <kanze@gabi-soft.de> wrote:

| I would suggest the following changes:
|
| In [lib.c.math], add a paragraph specifying that the C definition of
| rand shal be modified to say that "Unless otherwise specified, the
| implementation shall behave as if no library function calls the rand
| function."
|
| In [lib.alg.random.shuffle], add a sentence to the effect that "The two
| argument form of the function is the equivalent of calling the three
| parameter form with the function rand [lib.c.math] as the third
| parameter.  [Note: if the number of elements in the sequence is larger
| than RAND_MAX, this may result in a less than random shuffling.]"
|
| Formally speaking, the note is probably not necessary, but it does make
| it clear that we were aware of the limitation, decided that it wasn't
| worth doing anything else about it, and that's life -- if you have more
| elements, it's your problem.  (There are some good solutions to this in
| boost, but it's not yet appropriate to mention them in the standard.)

I support these changes.  However I don't think the note about RAND_MAX
is necessary.  Multiple calls to rand can easily be made to extend the
range past RAND_MAX as necessary.

--
Howard Hinnant
Metrowerks

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]