<HTML><HEAD><TITLE>N1535=03-0118, Random Number Generators Issues List</TITLE></HEAD><BODY>

<CENTER>
<H1><A NAME="N1535=03-0118, Random Number Generators Issues List">N1535=03-0118, Random Number Generators Issues List</A></H1>
</CENTER>

<TABLE ALIGN="RIGHT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Document number:</I></B></TD>
<TD>&nbsp; N1535=03-0118</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; November 14, 2003</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Project:</I></B></TD>
<TD>&nbsp; Programming Language C++</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Reference:</I></B></TD>
<TD>&nbsp; ISO/IEC IS 14882:1998(E)</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Reply to:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD></TD>
<TD>&nbsp; Dinkumware, Ltd.</TD>
</TR>
<TR>
<TD></TD>
<TD>&nbsp; petebecker@acm.org</TD>
</TR>
</TABLE>
<BR CLEAR="ALL">

<HR>

<H2>Contents</H2>

<P><A HREF="#1">1</A> Confusing Text in Description of <CODE>v.min()</CODE><BR>
<A HREF="#2">2</A> Confusing and Incorrect Text in Description of <CODE>v.max()</CODE><BR>
<A HREF="#3">3</A> Table &quot;Number Generator Requirements&quot; Unnecessary<BR>
<A HREF="#4">4</A> Should a <CODE>variate_generator</CODE> Holding a Reference Be Assignable?<BR>
<A HREF="#5">5</A> Normal Distribution Incorrectly Specified<BR>
<A HREF="#6">6</A> Should Random Number Initializers Take Iterators by Reference or by Value?<BR>
<A HREF="#7">7</A> Are Global Operators Overspecified?<BR>
<A HREF="#8">8</A> Should the Template Arguments Be Restricted to Built-in Types?<BR>
<A HREF="#9">9</A> Do Engines Need Type Arguments?<BR>
<A HREF="#10">10</A> Unclear Complexity Requirements for <CODE>variate_generator</CODE><BR>
<A HREF="#11">11</A> <CODE>xor_combine</CODE> Over-generalized?<BR>
<A HREF="#12">12</A> <CODE>xor_combine::result_type</CODE> Incorrectly Specified<BR>
<A HREF="#13">13</A> <CODE>subtract_with_carry</CODE>'s <CODE>IntType</CODE> Overpecified<BR>
<A HREF="#14">14</A> <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Missing Constaint<BR>
<A HREF="#15">15</A> <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Produces Bad Values<BR>
<A HREF="#16">16</A> <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Argument Type Too Small<BR>
<A HREF="#17">17</A> <CODE>subtract_with_carry::seed(In&amp;, In)</CODE> Required Sequence Length Too Long<BR>
<A HREF="#18">18</A> <CODE>linear_congruential</CODE> -- Giving Meaning to a Modulus of 0<BR>
<A HREF="#19">19</A> <CODE>linear_congruential::seed(IntType)</CODE> -- Modify Seed Value When <CODE>c == 0</CODE>?<BR>
<A HREF="#20">20</A> <CODE>linear_congruential</CODE> -- Should the Template Arguments Be Unsigned?<BR>
<A HREF="#21">21</A> <CODE>linear_congruential::linear_congruential(In&amp;, In)</CODE> -- Garbled Requires Clause<BR>
<A HREF="#22">22</A> <CODE>bernoulli_distribution</CODE> Isn't Really a Template<BR>
<A HREF="#23">23</A> Streaming Underspecified<BR>
</P>

<HR>

<H2>Active Issues</H2>

<HR><H3><A NAME="1">1</A>. Confusing Text in Description of <CODE>v.min()</CODE></H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.1 [tr.rand.req], Table 5.2</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> In "Uniform Random Number Requirements"
the text says that <CODE>v.min()</CODE>
&quot;Returns ... l where l is ...&quot;. This is the letter ell,
which is too easily confused with the numeral one. Can we change it
to something less confusing, like &quot;lim&quot;?</P>

<P><I>Jens Maurer says</I>: Sure.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the first sentence of the description
of <CODE>v.min()</CODE> in 5.1.1 [tr.rand.req], Table 5.2
(Uniform random number generator requirements) from:</P>

<BLOCKQUOTE>Returns some <CODE>l</CODE> where <CODE>l</CODE> is less than
or equal to all values potentially returned by <CODE>operator()</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>Returns a value that is less than or equal to all values
potentially returned by <CODE>operator()</CODE>.</BLOCKQUOTE>

<HR><H3><A NAME="2">2</A>. Confusing and Incorrect Text in Description of <CODE>v.max()</CODE></H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.1 [tr.rand.req], Table 5.2</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> In &quot;Uniform Random Number Requirements&quot;
the text says that <CODE>v.max()</CODE>
&quot;returns <CODE>l</CODE> where <CODE>l</CODE> is less than or equal to
all values...&quot;. Should this be &quot;greater than or equal to&quot;? And similarly,
should &quot;strictly less than&quot; be &quot;strictly greater than.&quot;?</P>

<P><I>Jens Maurer says:</I> Yes, cut&amp;paste goof from <CODE>v.min()</CODE>.</P>

<P><I>Pete Becker says:</I> And, as in the previous issue, <CODE>l</CODE> is unclear.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the first sentence of the description
of <CODE>v.max()</CODE> in 5.1.1 [tr.rand.req], Table 5.2
(Uniform random number generator requirements) from:</P>

<BLOCKQUOTE>If <CODE>std::numeric_limits&lt;T&gt;::is_integer</CODE>,
returns <CODE>l</CODE> where <CODE>l</CODE> is less than or equal to
all values potentially returned by <CODE>operator()</CODE>, otherwise,
returns <CODE>l</CODE> where <CODE>l</CODE> is strictly less than
all values potentially returned by <CODE>operator()</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>If <CODE>std::numeric_limits&lt;T&gt;::is_integer</CODE>,
returns a value that is greater than or equal to
all values potentially returned by <CODE>operator()</CODE>, otherwise,
returns a value that is strictly greater than
all values potentially returned by <CODE>operator()</CODE>.</BLOCKQUOTE>

<HR><H3><A NAME="3">3</A>. Table &quot;Number Generator Requirements&quot; Unnecessary</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.1 [tr.rand.req], Table 5.1</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The table "Number Generator Requirements" has only
one entry: <CODE>X::result_type</CODE>. While it's true that random nunber
generators and random distributions have this member, it doesn't seem like a
useful basis for classification -- there's nothing in the proposal that depends
on knowing that some type satisfies this requirement. I think the specification
of <CODE>X::result_type</CODE> should be in "Uniform Random Number
Generator Requirements" and in "Random Distribution Requirements."</P>

<P><B>Proposed Resolution:</B></P>

<P>Copy the description of <CODE>X::result_type</CODE> from 5.1.1 [tr.rand.req], Table 5.1
(Number generator requirements) to 5.1.1 [tr.rand.req], Table 5.2 (Uniform random number
generator requirements) and to 5.1.1 [tr.rand.req], Table 5.4 (Random distribution requirements)
and remove 5.1.1 [tr.rand.req], Table 5.1 (Number generator requirements).</P>

<HR><H3><A NAME="4">4</A>. Should a <CODE>variate_generator</CODE> Holding a Reference Be Assignable?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.3 [tr.rand.var]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The third paragraph says, in part:</P>

<BLOCKQUOTE>Specializations of <CODE>variate_generator</CODE> satisfy the
requirements of CopyConstructible. They also satisfy the requirements of
Assignable unless the template parameter <CODE>Engine</CODE> is of
the form <CODE>U&amp;</CODE>.</BLOCKQUOTE>

<P>I haven't thought this through carefully, but this looks like an
implementation artifact. Is there a reason that variate_generators whose
engine type is a reference should not be copied?</P>

<P><I>Jens Maurer says:</I> Not that I remember, except the implementation
hickup. As you point out, that can be easily worked around. I need to think
a little more on that.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the first two sentences of the third paragraph of 5.1.3 [tr.rand.var] from:</P>

<BLOCKQUOTE>Specializations of <CODE>variate_generator</CODE> satisfy the
requirements of CopyConstructible. They also satisfy the requirements of
Assignable unless the template parameter <CODE>Engine</CODE> is of
the form <CODE>U&amp;</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>Specializations of <CODE>variate_generator</CODE> satisfy the
requirements of CopyConstructible and Assignable.</BLOCKQUOTE>

<HR><H3><A NAME="5">5</A>. Normal Distribution Incorrectly Specified</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.7.8 [tr.rand.dist.norm]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> For <CODE>normal_distribution</CODE>, the paper says that
the probability density function is
<CODE>1/sqrt(2*pi*sigma) * exp(- (x - mean)^2 / (2 * sigma^2))</CODE>.
The references I've seen have a different initial factor, using
<CODE>1/(sqrt(2*pi) * sigma)</CODE>. That is, <CODE>sigma</CODE> is outside the
square root. Should we change the description in the paper to match?</P>

<P><I>Marc Paterno says:</I> The correct probability density function is as
Pete gives it, and the paper should be changed to match.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the first paragraph of 5.1.7.8 [tr.rand.dist.norm] from:</P>

<BLOCKQUOTE>A <CODE>normal_distribution</CODE> random distribution produces random
numbers <CODE>x</CODE> distributed with probability density function
<CODE>(1/sqrt(2*pi*sigma))e<SUP>-(x-mean)2/(2*sigma<SUP>2</SUP>)</SUP></CODE>,
where <CODE>mean</CODE> and <CODE>sigma</CODE> are the parameters of the
distribution.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>A <CODE>normal_distribution</CODE> random distribution produces random
numbers <CODE>x</CODE> distributed with probability density function
<CODE>(1/(sqrt(2*pi)*sigma))e<SUP>-(x-mean)2/(2*sigma<SUP>2</SUP>)</SUP></CODE>,
where <CODE>mean</CODE> and <CODE>sigma</CODE> are the parameters of the
distribution.</BLOCKQUOTE>

<HR><H3><A NAME="6">6</A>. Should Random Number Initializers Take Iterators by Reference or by Value?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.1 [tr.rand.eng.lcong]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.2 [tr.rand.eng.mers]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.3 [tr.rand.eng.sub]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.4 [tr.rand.eng.sub1]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.5 [tr.rand.eng.disc]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.6 [tr.rand.eng.xor]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I>The random number generators can be initialized and seeded
by passing two iterators that specify a range of values. The first
iterator is passed by reference and not by value. The reason
for doing this is things like <CODE>xor_combine</CODE>, which holds two generators, and needs
to initialize both generators from a single sequence:</P>

<PRE>template &lt;class _Engine1, class _Engine2&gt; // simplified
    class xor_combine
    {
    public:
        template &lt;class _InIt&gt;
        xor_combine(_Init& _First, _InIt _Last)
        	: _Eng1(_First, _Last), _Eng2(_First, _Last) {}
    private:
        _Engine1 _Eng1;
        _Engine2 _Eng2;
    };</PRE>

<P>With this, <CODE>_Eng1</CODE> is initialized with the values at the head of the sequence,
and <CODE>_Eng2</CODE> is initialized with the values that follow the ones that
<CODE>_Eng1</CODE> consumed.</P>

<P>That looks like a good idea, but there's a problem. It means that the
following code is ill-formed:</P>

<PRE>unsigned long init[] = { 1, 2, 3 };
minstd_rand rng0(init, init + 3);	// illegal, init not a modifiable lvalue
minstd_rand rng1;
rng1.seed(init, init + 3);		// illegal, init not a modifiable lvalue</PRE>

<P>It seems to me that this is what most users will try first (I did), and it's
surprising that it fails. It also seems like it would be the most common form of
initialization if it worked.</P>

<P>This can be made to work by passing the first iterator by value, and changing
<CODE>seed</CODE> to return an iterator in the usual way: it returns the iterator
that points to the element just past the last one it used. With just this change,
the constructor for <CODE>xor_combine</CODE> looks like this:

<PRE>template &lt;class _InIt&gt;
xor_combine(_InIt _First, _InIt _Last)
	: _Eng1, _Eng2
	{
	_InIt _Next = _Eng1.seed(_First, _Last);
	_Eng2.seed(_Next, _Last);
	}</PRE>

<P>An obvious drawback with this approach is that each contained generator gets
default initialized, then re-seeded. If that's a big enough problem (seeding some
generators might be computationally expensive), we could add an additional constructor
to each generator. The constructor is called with a value of some designated type, and
doesn't do any more initialization than is necessary to make the object destructible:</P>

<PRE>class rng_no_init_t {} rng_no_init;

template &lt;class _InIt&gt;
xor_combine(_InIt _First, _InIt _Last)
	: _Eng1(rng_no_init), _Eng2(rng_no_init)
	{
	_InIt _Next = _Eng1.seed(_First, _Last);
	_Eng2.seed(_Next, _Last);
	}</PRE>

<P>Of course, that constructor would only be used in this sort of situation, where
re-seeding will occur before any actual use of the generator.</P>

<P><I>Jens Maurer says:</I> I don't know how to put it in standardese,
but the idea is that the unsuspecting user should use the one-argument
integer constructor, i.e. <CODE>minstd_rand rng0(42)</CODE>, to likely
get reasonable seeding.  All base engines provide a constructor like this.
The <CODE>(it1,it2)</CODE> constructors were meant for &quot;expert&quot; users that
wanted fine-grained control over seeding.  It appears unlikely that those
&quot;expert&quot; users would use a fixed C-like array of seeds and could not be
bothered to introduce an additional local variable for the lvalue <CODE>it1</CODE>.</P>

<P>Let's investigate what [the suggested change] means:</P>

<P><CODE>rng_no_init_t</CODE> has to be accessible by the
compound engine's constructor definition (e.g. <CODE>xor_combine</CODE>)
and the declaration of the constructor in the base engine
(e.g. <CODE>_Eng1</CODE>). Together with the prospect of the end user
writing additional compound or base engines that should
combine freely with the library-provided ones, that means that
<CODE>rng_no_init_t</CODE> cannot be an implementation defined or class-
private type.  It has to be publicy specified.</P>

<P>In order to allow free combination of engines, the
&quot;pseudo-random number engine&quot; requirements must require,
for each engine, a constructor taking an <CODE>rng_no_init_t</CODE>.
The <CODE>operator()</CODE>, together with &lt;&lt; and &gt;&gt; streaming operators,
would then be specified to have undefined behavior until
the next successful call to <CODE>seed()</CODE>, if the object was
constructed using <CODE>rng_no_init_t</CODE>.</P>

<P>While this can certainly be done, it leaves the odd
feeling that we would deliberately introduce a constructor
that starts the lifetime of the object, but leaves the
object semantically unusable (internal state uninitialized).
This is not what I thought user-defined constructors were
meant for.  There is the potential for misuse by the
user, if he constructs an object with the public <CODE>rng_no_init_t</CODE>
constructor without calling a <CODE>seed()</CODE> function afterwards.
Calls to <CODE>operator()</CODE> would likely return apparently
&quot;random&quot; numbers, because on most platforms, accessing
uninitialized variables means reading &quot;random&quot; garbage.
However, none of the assertions of the engine's specification
would be met. It is possible that this misuse is not detected except by
careful code review.  On the other hand, the misuse in your
first example is caught by the compiler.  Problems caught
by the compiler are cheapest to fix, compared to runtime
problems.</P>

<P>I'm not particularly fond of the current <CODE>(it1,it2)</CODE>
interface, either, but, given the constraints of
constructors, it's the only interface I could come up
with (see discussion in section III.E of N1452).</P>

<P>I would appreciate hearing other people's opinion on
this, in particular the perceived &quot;ugliness&quot; of the
<CODE>long[]</CODE> initialization in the example above.</P>

<P><I>Pete Becker says:</I> With regard to &quot;expert&quot; users,
it's not so much a matter of could not be bothered, as it is find it surprising.
It's a range, and we don't require an lvalue as the first iterator to a range anywhere else.</P>

<P>It may be that this is intended for expert users, but STL-conscious folks
will see iterators and use them.</P>

<P>My suggestion uses a fairly common idiom, called &quot;two-phase initialization.&quot;
I agree it's better to avoid it, but I don't see any other way to avoid the non-intuitive
semantics of requiring an lvalue for an iterator.</P>

<P>With regard to the &quot;ugliness&quot; of the initialization, here's the way
to do it currently:</P>

<PRE>    unsigned long init[] = { 1, 2, 3 };
    unsigned long *lval_init = init;
    minstd_rand rng(lval_init, init + 3);</PRE>

<P>Here's what I'd like to be able to do:</P>

<PRE>    unsigned long init[] = { 1, 2, 3 };
    minstd_rand rng(init, init + 3);</PRE>

<P><I>Peter Dimov says:</I> This is, to me, an interesting issue WRT
the move/forwarding proposal.</P>

<P>Part of the problem is that <CODE>It&</CODE> will not bind to rvalues, as in the example
below:</P>

<PRE>    vector&lt;unsigned long&gt; v;
    // read v
    minstd_rand rng(v.begin(), v.end());</PRE>

<P>This can be fixed by making the first argument <CODE>It &&</CODE> when, or if, the rvalue
reference is accepted.</P>

<P>The second half of the problem is that in</P>

<PRE>    unsigned long init[] = { 1, 2, 3 };
    minstd_rand rng(init, init + 3);</PRE>

<P><CODE>init</CODE> is an lvalue of type <CODE>unsigned long [3]</CODE>, and <CODE>init + 3</CODE>
is an rvalue of type <CODE>unsigned long *</CODE>; even an rvalue reference-based interface will fail
deduction.</P>

<P>This can be fixed by, for example, adding a constructor that takes <CODE>T (&amp;)[N]</CODE>.</P>

<P><I>Pete Becker says:</I> Or by writing the code correctly &lt;g&gt;:</P>

<PRE>    minstd_rand rng(&init[0], init + 3);</PRE>

<P>In any case, my concern is to be able to write code that looks like the
analogous use of sequences in other parts of the library.</P>

<P><I>Bjarne Stroustrup says:</I> and that's an important concern.</P>

<HR><H3><A NAME="7">7</A>. Are Global Operators Overspecified?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.1 [tr.rand.req]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> Table 5.3 (Pseudo-random number engine requirements)
says that for every engine, each of the following must be valid:</P>

<PRE>    x == y
    x != y
    os &lt;&lt; x
    is &gt;&gt; x</PRE>

<P>In addition, though, each of the four engines is specified as having a global
operator for each of these operations, taking the engine type as appropriate.</P>

<P>Technically that means that I can't, for example, implement
<CODE>subtract_with_carry</CODE> and <CODE>subtract_with_carry_01</CODE> using a
single template (suitably parametrized) as a base class, and supply the appropriate
global operators for that base template. Some smart-aleck conformance test
writer &lt;g&gt; will check for the precise signature, find that it's not there,
and report a conformance failure.</P>

<P>So, do we want just the operational requirement that <CODE>x == y</CODE>
must work, or do we want the more specific requirement that for each engine
type there must be a corresponding <CODE>operator==</CODE>?</P>

<P><I>Marc Paterno says:</I> I think the ability to test for equality
(or inequality) is important, but that the way it is implemented should be
up to the implementer. So I'm happy with the operational requirement that
<CODE>x == y</CODE> must work, but see no need to require any specific signature.</P>

Peter Dimov:

<P><I>Peter Dimov says:</I> If</P>

<PRE>    template&lt;class T&gt; bool operator==(T const &, T const &) { return false; }</PRE>

<P>is in scope,</P>

<PRE>    x == y</PRE>

<P>will go to that template instead of the base class version.</P>

<P>One possible use for introducing such an operator is to use <CODE>x == y</CODE> in cases
where <CODE>decltype(x)</CODE> does not have an <CODE>operator==</CODE>. This technique
is very rare and fragile, though.</P>

<P><I>Pete Becker says:</I> I wouldn't have put it so delicately. I have no
sympathy for someone who deliberately breaks inheritance relationships with that
sort of $"#*$*&. Templates are a delicate tool, not a sledgehammer.</P>

<P><I>Peter Dimov says:</I> I'm not sure whether I expressed myself well.
I'll try again with code.</P>

<PRE>    namespace hidden
    {
    template&lt;class T&gt; bool operator==(T const &, T const &)
        { return false; }
    }

    template&lt;class X&gt; bool compare(X const & x, X const & y)
    {
    using namespace hidden;
    return x == y;
    }

    struct V {}; // no operator==

    #include &lt;iostream&gt;

    int main()
    {
    V v1, v2;
    // v1 == v2; // error

    std::cout &lt;&lt; compare(1, 1) &lt;&lt; std::endl;
    std::cout &lt;&lt; compare(v1, v2) &lt;&lt; std::endl;
    }</PRE>

<P>So the &quot;evil&quot; template <CODE>operator==</CODE> is delicately
applied in <CODE>compare</CODE> (being selectively made visible only at the
scope of the function) to build a comparison that yields false when there is
no <CODE>operator==</CODE> defined for the type.</P>

<P>I'll leave it to others to judge whether this technique is worth supporting.</P>

<P><I>Pete Becker says:</I> Doesn't change my reaction. It's still a sledgehammer.
There are things that library designers ought to take into account and things
that users should know are risky. Writing templates as if the language did not have
inheritance is risky. Anyone who does this will have to pick up the pieces
of the code that they broke.</P>

<HR><H3><A NAME="8">8</A>. Should the Template Arguments Be Restricted to Built-in Types?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp;</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> Generators and distributions are all parametrized
on arithmetic types, named <CODE>RealType</CODE>, <CODE>IntType</CODE>,
and <CODE>UIntType</CODE>. The proposal describes these types in terms
of the operations that can be applied to them and the functions that can be called
on them. So, for example,</P>

<BLOCKQUOTE>A template parameter named <CODE>IntType</CODE> shall denote a
type that represents an integer number. This type shall
meet the requirements for a numeric type (26.1
[lib.numeric.requirements]), the binary operators +, -, *, /, %
shall be applicable to it, and a conversion from int shall
exist. [Footnote: The built-in types int and long meet these requirements.]</BLOCKQUOTE>

<P>The idea, I assume, is to support user-defined types that look like integer types.
Although it doesn't say so, the requirement seems to be that the algorithm be
implemented with the user-defined type, since some of the parameters for the
algorithm (specified as template arguments or as arguments to the ctor) are
<CODE>IntType</CODE>, and there is no conversion required from <CODE>IntType</CODE>
to any of the built-in types. This is a fairly severe constraint on implementors.
Is it worth it?</P>

<P>It's easy to go astray here. For example the Boost implementation of
<CODE>uniform_int</CODE> uses <CODE>std::numeric_limts&lt;IntType&gt;</CODE>,
it uses &lt;, ++, &lt;=, +=, *=, ==, &gt;. It also applies a <CODE>static_cast</CODE>
to convert the <CODE>result_type</CODE> of the distribution (typedefed to 
<CODE>IntType</CODE>) into the <CODE>result_type</CODE> of the underlying
random number generator. These operations cannot be expected to work under
the constraints given above.</P>

<P>I'm not picking on the Boost implementation here: our implementation does the same
sorts of things. The point is that specifying what an integer type ought to look
like is hard. If we don't get it right there will be techniques that work just
fine on built-in types but can't be used because user-defined types aren't required
to support them.</P>

<P>Another example comes from the floating point types. Some of the distributions can
be implemented with techniques that count the number of high-order 0 bits in the
binary fraction that represents a value between 0.0 and 1.0. That can be fast and
cheap if I know that the type being used is the platform's builtin floating point
type, because I can look at the bits directly instead of using floating point math.</P>

<P>Of course, these optimization techniques can be applied through partial specialization,
so that the optimized versions are &quot;only&quot; used for builtin types, and sub-optimal
versions are available for user-defined types. That means that library vendors
will have to supply code that's difficult to test and will never (rarely?) be used.</P>

<P>How important is this? Would it be sufficient to say that <CODE>RealType</CODE>
means one of <CODE>float</CODE>, <CODE>double</CODE>, <CODE>long double</CODE>
(which is, in essence, what we say for <CODE>complex</CODE>),
<CODE>IntType</CODE> is either <CODE>int</CODE> or <CODE>long</CODE>,
and <CODE>UIntType</CODE> is either <CODE>unsigned int</CODE> or <CODE>unsigned long</CODE>?</P>

<HR><H3><A NAME="9">9</A>. Do Engines Need Type Arguments?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp;</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> Issue number 8 gives reasons for restricting the
type arguments to builtin types. If we do this, it turns out that the type
arguments for engines are pretty much redundant. I'm not clear yet on whether
they're needed for distributions, so I'm only talking here about engines.</P>

<P>The implementation can always determine an appropriate type from the other arguments
to the engine templates. For example, <CODE>mersenne_twister</CODE> takes an argument
that gives the number of bits in each word. The implementor is in the best position to decide
what type to use to represent that number of bits. A user trying to write portable
code won't ever specify any type other than <CODE>unsigned long</CODE> for a 32-bit
mersenne twister, because portable code can't assume that any other type can hold a 32 bit
value. The standard library implementor can do better, avoiding gratuitously large types.</P>

<P>Part of the issue here is an assumption in the proposal that these templates should
be implemented using the user-specified type internally. For builtin types, the
type used internally isn't detectable provided the algorithm is implemented
correctly. And there are potentially large performance gains from, for example,
implementing a linear congruential generator that returns 32-bit values using a
64-bit type internally. The <I>as-if</I> rule means that the user-specified type is
essentially irrelevant to the implementation, and any good implemenation will
make at least as good a choice here as the user can, and usually better.</P>

<P>The other place where the user-specified type appears is in the return type of
<CODE>operator()</CODE>. So, for example, <CODE>linear_congruential</CODE> requires
the user to supply a type that's large enough to hold values in the range from 0 to <CODE>m-1</CODE>.
But the implementation can determine an appropriate type based on the value of <CODE>m</CODE>, so
what's gained by requiring the user to specify this type?</P>

<HR><H3><A NAME="10">10</A>. Unclear Complexity Requirements for <CODE>variate_generator</CODE></H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.3 [tr.rand.var]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The specification for <CODE>variate_generator</CODE>
says</P>

<BLOCKQUOTE>Specializations of <CODE>variate_generator</CODE> satisfy the requirements of
CopyConstructible. They also satisfy the requirements of Assignable unless the template
parameter <CODE>Engine</CODE> is of the form <CODE>U&amp;</CODE>. The complexity of
all functions specified in this section is constant. No function described in this
section except the constructor throws an exception.</BLOCKQUOTE>

<P>Taken literally, this isn't implementable. <CODE>operator()</CODE> calls
the underlying distribution's <CODE>operator()</CODE>, whose complexity isn't
directly specified. The distribution's <CODE>operator()</CODE> makes an amortized constant
number of calls to the generator's <CODE>operator()</CODE>, whose complexity is,
again, amortized constant. So the complexity of <CODE>variate_generator::operator()</CODE>
ought to also be amortized constant.</P>

<P><CODE>variate_generator</CODE> also has a constructor that takes an engine and a
distribution by value, and uses their respective copy constructors to
create internal copies. There are no complexity constraints on those
copy constructors, but given that the default constructor for an engine
has complexity O(size of state), it seems likely that an engine's copy
constructor would also have complexity O(size of state). This means that
<CODE>variate_generator</CODE>'s complexity is at best O(size of engine's state),
not constant.</P>

<P>I suspect that what was intended was that these functions would not introduce any
additional complexity, that is, their complexity is the &quot;larger&quot; of the
complexities of the functions that they call.</P>

<HR><H3><A NAME="11">11</A>. <CODE>xor_combine</CODE> Over-generalized?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.6 [tr.rand.eng.xor]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> For an <CODE>xor_combine</CODE> engine, is there
ever a case where both <CODE>s1</CODE> and <CODE>s2</CODE> would be non-zero?
Seems like this would produce non-random values, because the low bits
(up to the smaller of the two shift values) would all be 0.</P>

<P><I>Jens Maurer says:</I> Yes, indeed. Good spotting. A case of over-generalization
on my part.</P>

<P><I>Pete Becker says:</I> If at least one has to be 0, then we only need
one shift value, and the definition might look more like this:
 
<PRE>    template &lt;class _Engine1, class _Engine2, int _Shift = 0&gt; ...</PRE>
 
<P>with the output being <CODE>(_Eng1() ^ (_Eng2() &lt;&lt; _Shift))</CODE>.</P>

<P><I>Jens Maurer says:</I> That requires that <CODE>Eng1</CODE> is the engine
associated with the 0 shift, so it enforces a specific ordering of arguments
which might not match the user-desired initialization ordering with the dreadful
<CODE>seed(it1,it2)</CODE> interface.  But that appears as a minor drawback
compared to the simplified interface.</P>

<P><I>See also:</I> <A HREF="#another argument">another argument</A></P>

<HR><H3><A NAME="12">12</A>. <CODE>xor_combine::result_type</CODE> Incorrectly Specified</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.6 [tr.rand.eng.xor]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> <CODE>xor_combine</CODE> has a member</P>

<PRE> typedef typename base_type::result_type result_type;</PRE>

<P>However, it has no type named <CODE>base_type</CODE>, only <CODE>base1_type</CODE>
and <CODE>base2_type</CODE>. So, what should result_type be?</P>

<P><I>Jens Maurer says:</I> <CODE>base1_type</CODE>, by &quot;random&quot; choice.</P>

<P>(That's <B><A NAME="another argument">another argument</A></B> why you may
want to have the freedom of reordering the base engine types in the interface:
With the current interface, it's easy to get <CODE>base2_type</CODE>, just reorder.
When we have only one shift count, reordering changes the
shifting.)</P>

<P><I>Pete Becker says:</I> Could be. I think there are a couple of other
reasonable result types, though: the larger of the two types might be appropriate,
or the actual type of the computed result. Neither of these depends on the order
of the engine arguments.</P>

<HR><H3><A NAME="13">13</A>. <CODE>subtract_with_carry</CODE>'s <CODE>IntType</CODE> Overpecified</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.3 [tr.rand.eng.sub]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The IntType for subtract_with_carry
&quot;shall denote a signed integral type large enough
to store values up to <CODE>m - 1</CODE>.&quot; The implementation subtracts
two values of that type, and if the result is <CODE>&lt; 0</CODE> it adds back
the <CODE>m</CODE>, which makes the result non-negative. In fact, this also
works for unsigned types, with just a small change in the implementation:
instead of testing whether the result is <CODE>&lt; 0</CODE> you test whether it's
<CODE>&lt; 0</CODE> or greater than or equal to <CODE>m</CODE>. This works because
unsigned arithmetic wraps, and it makes the template a bit easier to use.</P>

<P>I suggest that we loosen the constraint to allow signed and unsigned types. Thus the
constraint would read &quot;shall denote an integral type large enough to store values
up to <CODE>m - 1</CODE>.&quot;</P>

<P><B>Proposed Resolution:</B></P>

<P>Change:</P>

<BLOCKQUOTE>The template parameter <CODE>IntType</CODE> shall denote a
signed integral type large enough to store values up to <CODE>m-1</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>The template parameter <CODE>IntType</CODE> shall denote an
integral type large enough to store values up to <CODE>m-1</CODE>.</BLOCKQUOTE>

<HR><H3><A NAME="14">14</A>. <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Missing Constaint</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.4 [tr.rand.eng.sub1]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The specification for
<CODE>subtract_with_carry::seed(IntVal)</CODE> has a <I>Requires</I>
clause which requires that the argument be greater than 0. This member
function needs the same constraint.</P>

<P><B>Proposed Resolution:</B></P>

<P>Add:</P>

<BLOCKQUOTE><B>Requires:</B> <CODE>value &gt; 0</CODE></BLOCKQUOTE>

<P>to the description of <CODE>subtract_with_carry_01::seed(unsigned)</CODE>
in 5.1.4.4 [tr.rand.eng.sub1].</P>

<HR><H3><A NAME="15">15</A>. <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Produces Bad Values</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.4 [tr.rand.eng.sub1]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> <CODE>subtract_with_carry_01::seed(unsigned int)</CODE>
uses a linear congruential generator to produce initial values for the fictitious
previously generated values. These values are generated as <CODE>(y(i)*2^-w) mod 1</CODE>.
The linear congruential generator produces values in the range <CODE>[0, 2147483564)</CODE>,
which are at most 31 bits long. If the template argument <CODE>w</CODE> is greater
than 31 the initial values generated by seed will all be rather small, and the first
values produced by the generator will also be rather small. The Boost implementation avoids
this problem by combining values from the linear congruential generator to
produce longer values when <CODE>w</CODE> is larger than 32. Should we require something
more like that?</P>

<HR><H3><A NAME="16">16</A>. <CODE>subtract_with_carry_01::seed(unsigned)</CODE> Argument Type Too Small</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.4 [tr.rand.eng.sub1]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> <CODE>subtract_with_carry_01::seed(unsigned)</CODE>
has a default argument value of 19780503, which is too large to fit in a
16-bit unsigned int. Should this argument be unsigned long, to ensure that
it's large enough for the default?</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the signatures of this constructor and member function:</P>

<PRE>    subtract_with_carry_01(unsigned int value);
    void seed(unsigned int value = 19780503);</PRE>

<P>to:</P>

<PRE>    subtract_with_carry_01(unsigned long value);
    void seed(unsigned long value = 19780503);</PRE>

<HR><H3><A NAME="17">17</A>. <CODE>subtract_with_carry::seed(In&amp;, In)</CODE> Required Sequence Length Too Long</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.3 [tr.rand.eng.sub]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"></TD>
<TD>&nbsp; 5.1.4.4 [tr.rand.eng.sub1]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> For both <CODE>subtract_with_carry::seed(In& first, In last)</CODE>
and <CODE>subtract_with_carry_01::seed(In& first, In last)</CODE>
the proposal says: &quot;With <CODE>n=w/32+1</CODE> (rounded downward) and given the
values <CODE>z0 ... zn*r-1</CODE>.&quot; The idea is to use <CODE>n</CODE>
<CODE>unsigned long</CODE> values to generate each of the initial values for the
generator, so <CODE>n</CODE> should be the number of 32-bit words needed to
provide <CODE>w</CODE> bits. Looks like it should be &quot;<CODE>n=(w+31)/32</CODE>&quot;.
As currently written, when <CODE>w</CODE> is 32, the function consumes two 32-bit values for each
value that it generates. One is sufficient.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change</P>

<BLOCKQUOTE>With <CODE>n=w/32+1</CODE> (rounded downward) and given the
values <CODE>z0 ... zn*r-1</CODE></BLOCKQUOTE>

<P>to</P>

<BLOCKQUOTE>With <CODE>n=(w+31)/32</CODE> (rounded downward) and given the
values <CODE>z0 ... zn*r-1</CODE></BLOCKQUOTE>

<P>in the description of <CODE>subtract_with_carry::seed(In& first, In last)</CODE>
in 5.1.4.3 [tr.rand.eng.sub] and in the description of
<CODE>subtract_with_carry_01::seed(In& first, In last)</CODE> in 5.1.4.4 [tr.rand.eng.sub1].</P>

<HR><H3><A NAME="18">18</A>. <CODE>linear_congruential</CODE> -- Giving Meaning to a Modulus of 0</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.1 [tr.rand.eng.lcong]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> Some linear congruential generators using an
integral type <CODE>_Ty</CODE> also use a modulus that's equal to
<CODE>numeric_limts&lt;_Ty&gt;::max() + 1</CODE> (e.g. 65536 for a
16-bit unsigned int). There's no way to write this value as a constant
of the type <CODE>_Ty</CODE>, though. Writing it as a larger type
doesn't work, because the linear_congruential template expects an
argument of type <CODE>_Ty</CODE>, so you typically end up with a value
that looks like 0.</P>

<P>On the other hand, the current text says that the effect
of specifying a modulus of 0 for <CODE>linear_congruential</CODE> is
implementation defined. I decided to use 0 to mean <CODE>max()+1</CODE>,
as did the Boost implementation. (Internally, the implementation of
<CODE>mersenne_twister</CODE> needs a generator with a modulus like
this). Seems to me this is a reasonable choice, and one that
users ought to be able to rely on. Is there some other meaning that might
reasonably be ascribed to it, or should we say that a modulus of 0 means
<CODE>numeric_limits&lt;_Ty&gt;::max() + 1</CODE> (suitably type-cast)?</P>

<HR><H3><A NAME="19">19</A>. <CODE>linear_congruential::seed(IntType)</CODE> -- Modify Seed Value When <CODE>c == 0</CODE>?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.1 [tr.rand.eng.lcong]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> When c == 0 you get a generator with a slight quirk:
if you seed it with 0 you get 0's forever; if you seed it with a non-0 value
you never get 0. The first path, of course, should be avoided. The proposal
does this by imposing a requirement on <CODE>seed(IntType x0)</CODE>,
requiring that <CODE>c &gt; 0 || (x0 % m) &gt; 0</CODE>.
The boost implementation uses asserts to check this condition.
The only reservation I have about this is that it can only be checked at runtime,
when the only suitable action is, probably, to abort. An alternative would be to
force a non-0 seed in that case (perhaps 1, for no particularly good reason). I think
the second alternative is marginally better, and I suggest we change this requirement
to impose a particular seed value when a user passes 0 to a generator with <CODE>c == 0</CODE>.</P>

<P><B>Proposed Resolution:</B></P>

<P>In the text describing <CODE>void seed(IntType x0 = 1)</CODE> in 5.1.4.1 [tr.rand.eng.lcong]
remove the <I>Requires</I> clause and change the <CODE>Effects</CODE> clause from:</P>

<BLOCKQUOTE>Sets the state <CODE>x(i)</CODE> of the engine to <CODE>x0 mod m</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>Sets the state <CODE>x(i)</CODE> of the engine to
<CODE>(x0 == 0 && c == 0 ? 1 : x0) mod m</CODE>.</BLOCKQUOTE>

<HR><H3><A NAME="20">20</A>. <CODE>linear_congruential</CODE> -- Should the Template Arguments Be Unsigned?</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.1 [tr.rand.eng.lcong]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> This template takes three numeric arguments, <CODE>a</CODE>,
<CODE>c</CODE>, and <CODE>m</CODE>, whose type is <CODE>IntType</CODE>. <CODE>IntType</CODE>
is an integral type, possibly signed. These arguments specify the details of the recurrence
relation for the generator:</P>

<PRE>    x(i + 1) := (a * x(i) + c) mod m</PRE>

<P>Every discussion that I've seen of this algorithm uses unsigned values. Further,
In C and C++ there is no modulus operator. The result of the <CODE>%</CODE>
operator is implementation specific when either of its operands is negative, so
implementing <CODE>mod</CODE> when the values involved can be negative requires a
test and possible adjustment:</P>

<PRE>   IntType res = (a * x + c) % m;
    if (res &lt; 0)
        res += m;</PRE>

<P>If the three template arguments can't be negative the recurrence relation can be
implemented directly:</P>

<PRE>   x = (a * x + c) % m;</PRE>

<P>This makes the generator faster.</P>

<P><B>Proposed Resolution:</B></P>

<P>In clause 5.1.4.1 [tr.rand.eng.lcong] replace every occurrence of <CODE>IntType</CODE>
with <CODE>UIntType</CODE> and change the first sentence after the definition of the template
from:</P>

<BLOCKQUOTE>The template parameter <CODE>IntType</CODE> shall denote an integral type
large enough to store values up to <CODE>(m-1)</CODE>.</BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE>The template parameter <CODE>UIntType</CODE> shall denote an unsigned integral type
large enough to store values up to <CODE>(m-1)</CODE>.</BLOCKQUOTE>

<HR><H3><A NAME="21">21</A>. <CODE>linear_congruential::linear_congruential(In&amp;, In)</CODE> -- Garbled Requires Clause</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.4.1 [tr.rand.eng.lcong]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The <B>Requires</B> clause for the member template
<CODE>template &lt;class In&gt; linear_congruential(In&amp; first, In last)</CODE>
got garbled in the translation to .pdf format.</P>

<P><B>Proposed Resolution:</B></P>

<P>Change the <B>Requires</B> clause for the member template
<CODE>template &lt;class In&gt; linear_congruential(In&amp; first, In last)</CODE>
in 5.1.4.1 [tr.rand.eng.lcong] from:</P>

<BLOCKQUOTE><B>Requires:</B> <CODE>c &gt; 0  *first  0</CODE></BLOCKQUOTE>

<P>to:</P>

<BLOCKQUOTE><B>Requires:</B> <CODE>c &gt; 0 || *first &gt; 0</CODE></BLOCKQUOTE>

<HR><H3><A NAME="22">22</A>. <CODE>bernoulli_distribution</CODE> Isn't Really a Template</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.7.2 [tr.rand.dist.bern]</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The text says that <CODE>bernoulli_distribution</CODE>
is a template, parametrized on a type that is required to be a real type. Its
<CODE>operator()</CODE> returns a <CODE>bool</CODE>, with the probability
of returning true determined by the argument passed to the object's constructor.
The only place where the type parameter is used is as the type of the argument
to the constructor. What is the benefit from making this type user-selectable
instead of, say, double?</P>

<P><I>Marc Paterno says:</I> I don't see a good reason to make
<CODE>bernoulli_distribution</CODE> a template, and would be content to do
as Pete implies, and make the type parameter a double.</P>

<P><B>Proposed Resolution:</B></P>

<P>In 5.1.7.2 [tr.rand.dist.bern], remove <CODE>template &lt;class RealType = double&gt;</CODE>
from the declaration of <CODE>bernoulli_distribtion</CODE>, change the declaration of the
constructor from:</P>

<PRE>    explicit bernoulli_distribution(const RealType&amp; p = RealType(0.5));</PRE>

<P>to:</P>

<PRE>    explicit bernoulli_distribution(double p = 0.5);</PRE>

<P>and change the header for the subclause describing the constructor from:</P>

<PRE>    bernoulli_distribution(const RealType&amp; p = RealType(0.5))</PRE>

<P>to:</P>

<PRE>    bernoulli_distribution(double p = 0.5)</PRE>

<HR><H3><A NAME="23">23</A>. Streaming Underspecified</H3>

<TABLE ALIGN="LEFT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT"><B><I>Section:</I></B></TD>
<TD>&nbsp; 5.1.1 [tr.rand.req], Table 5.3</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Submitted by:</I></B></TD>
<TD>&nbsp; Pete Becker</TD>
</TR>
<TR>
<TD ALIGN="RIGHT"><B><I>Date:</I></B></TD>
<TD>&nbsp; October 16, 2003</TD>
</TR>
</TABLE>
<BR CLEAR="ALL"><BR>

<P><I>Pete Becker says:</I> The text in Table 5.3,
&quot;Pseudo-random Number Engine Requirements&quot; says: <CODE>os &lt;&lt; x</CODE>
specifies particular settings for <CODE>os.fmtflags</CODE> and the fill character.
We don't do that for, e.g., <CODE>complex&lt;whatever&gt;</CODE>, so this is a
departure from the &quot;usual&quot; interface. We may well need to be more
specific all around, but I think that ought to be done in the context of an
overall review of inserters for compound types, and not ad hoc.</P>

<P><I>Jens Maurer says:</I> That goes with the sentiment of the review that the
requirements are not specific enough to ensure portability of engine state
across platforms. Extending the requirements to be sufficiently paranoid
is probably too easy to get incomplete or wrong.</P>

<P><I>Pete Becker says:</I> I don't think it's practical to require state
IO to be portable across platforms. There are two problems: first, it imposes
contraints on how the algorithm is implemented; and second, it requires
conversion capabilities that are not required anywhere else in the standard.
I think &quot;mere&quot; binary IO is sufficient.</P>

<P>The biggest constraint that I see is that being able to write the state out
from one program and read it into another requires that the state be represented
in exactly the same way on all platforms. Hence the change in the implementation
of <CODE>subtract_with_carry</CODE> from Boost 1.29 to Boost 1.30.
<CODE>subtract_with_carry</CODE> generates a new value based on two earlier ones. \
Simplified, <CODE>x(i) := x(i - s) - x(i - r)</CODE> [where s &lt; r].
The obvious implementation is to keep the last <CODE>r</CODE> values, and on each call,
compute a new value and replace the old <CODE>x[r]</CODE> (which is no longer needed) with
the new one, so that it will be available when its needed later on. A somewhat
faster implementation (used in 1.29) precomputes <CODE>r</CODE> values, and steps through
the array returning values whenever requested. When the array index steps off
the end, new values are precomputed and the index gets reset to the beginning
of the array. This simplifies the index computations (<CODE>i-s</CODE> has to wrap around to
the top of the array), and perhaps allows unrolling of loops. Trouble is, if
you do this you can't write out the state of the generator as specified in
the proposal, because you've thrown it away. (Yes, you can hang on to the
old data after you precompute new values, if you're willing to double the
size of state data -- that's a high price to pay, especially for the mersenne
twister, whose most common instantiation uses 624 32-bit values) So 1.30 removed
this optimization from <CODE>subtract_with_carry</CODE> in order, apparently, to satisfy
the IO requirements.</P>

<P>The conversion problem is more subtle. In order to write out a floating point
value and read in exactly the same value you have to do some fairly sophisticated
(i.e. big and slow) semi-numerical work. Stream inserters and extractors for
floating point values are not currently required to support this degree of
accuracy, and as far as I know, none do. Further, this accuracy is incompatible
with fixed width formats. The general scheme is to write out as many digits as
are needed to distinguish the current value from the two nearest values, so
the width of the text representation of the values differs (you could compute
every value to the same maximum number of digits, but those extra digits require
more precision than the floating point type holds, so these extra digits require
multiple-precision integer math, which is rather slow). Beyond that, the number
of digits in the text representation depends on the precision of the floating
point type. In order to write values that can be read on any platform, it seems
to me that all implementations would have to write enough digits to represent
values of the largest type available anywhere. That's not a good recipe for
portability. &lt;g&gt;</P>

<P>It's not completely clear what the purpose of the inserters and extractors is.
The paper talks about engines and distributions that store their state and
recover it. It certainly makes sense that a computation might need to be
interrupted and resumed later. That doesn't require text representations,
nor exact reproducibility across platforms.</P>

<P>Would it make sense to instead require binary write and read functions,
subject to all the usual contraints on binary IO? That would mean that data
could only be read by a program compiled with the same compiler as the one
that wrote it. This also eliminates the contraints on the state (the
descriptions of the states are still important in defining what the
algorithms do, but the &quot;as-if&quot; rule would then permit alternate
implementations), while providing what seems to be the most commonly
used operation, namely interrupting a computation and resuming it later.</P>

<P><I>Marc Paterno says:</I> What is the reason for saving and restoring the
state in a portable fashion?</P>

<P>An important requirement is given in III.A. &quot;Overview on
Requirements&quot;: &quot;has a tight enough specification to get reliable
cross-platform results&quot;. In our view this is essential for engines,
but not for distributions. So we confine our comments to discussing
the portable saving and storing of state for engines.</P>

<P>One of the reasons for saving state is the checkpointing of
long-running calculations. For this, saving binary state is
sufficient, and portability is not an issue.</P>

<P>Another important reason for saving state is large-scale
parallelization of calculations. A calculation run on a farm (of
possibly dissimilar hardware) will need not only the same
checkpointing ability, but the ability to communicate the state from
one node to another. This doesn't require human readability (textual
representation), but it does require the ability to recover the
complete state of an engine from some external representation in a
portable fashion.</P>

<P>A third reason for saving the state is to reproduce a calculation on
another platform. Distributed computing applications using random
numbers for cryptography may need to generate the same sequence of
numbers, and may need to share the state of the engine, again
portably.</P>

<P>A fourth reason for saving the state is to allow for portable
reproducibility of results. In order to verify, explore and extend
simulation results, researchers require the ability to reproduce, from
a given checkpoint, the stream of random numbers the original
simulation relied upon.</P>

<P>We believe that this requirement does not demand that the state be
represented in exactly the same way on all platforms. It only implies
that an implementation-independent logical state exists. The manner in
which the physical state realizes this logical state is left to the
implementor.</P>

<P>In light of these requirements, we have reviewed the proposal, and
have come to the following conclusion. To completely specify the
behavior of an engine means answering the following 5 points:</P>

<BLOCKQUOTE>1) to have the logical state of each engine specified (this seems to
be done in the current proposal, perhaps with inconsistent notation);</BLOCKQUOTE>

<BLOCKQUOTE>2) to have a prescription for how to move from the current logical
state to the successor logical state (each engine in the current
proposal does this adequately);</BLOCKQUOTE>

<BLOCKQUOTE>3) to have a prescription to extract the random number to deliver
from the engine's logical state (each engine in the current proposal
does this adequately);</BLOCKQUOTE>

<BLOCKQUOTE>4) to have a prescription to map a sequence of unsigned longs to the
logical state of an engine (this is implied -- by the seed function
-- but insufficiently specified in the current proposal);</BLOCKQUOTE>

<BLOCKQUOTE>5) to have a prescription to map the current logical state into a
sequence of unsigned longs (this requirement is not clearly specified
by the current proposal).</BLOCKQUOTE>

<P>We believe capabilities (4) and (5) will enable portable saving and
restoring of state for engines. And we believe that portable saving
and restoring of state is sufficiently important to be worth the
effort.</P>

<P>Pete points out two specific cases in which he is concerned with cost
implied by requirement (5). We would classify this as a quality of
implementation issue. That is, it is up to the implementer to decide
whether the extra size of the physical state is worth the benefit of
speed gained by caching. The importance of the portable saving and
restoring is sufficiently high that it is worth incurring one or the
other of these costs.</P>

<P><I>Pete Becker says:</I> Now that you've explained why saving on one
platform and restoring on another is important, I think it's reasonable
to trade some speed or space for that capability. Of course, that doesn't
solve the problem of how to specify it. &lt;g&gt;</P>

<P>Part of the problem with specifying this is the requirement that generators
can be instantiated on arbitrary user-defined types. I think that's a bad
idea. But rather than argue about that, I'll just ignore the requirement for now.</P>

<P>Most of the generators store their state in integral types. Those are pretty easy
to deal with. For reproducibility across platforms, the state has to be described
in terms of values that will fit in 32 bits, since that's the largest type that
every C++ implementation is required to have. To save and restore across diverse
platforms, it's the same thing: if you go beyond 32 bits you're not portable. So
the requirement here is straightforward: write and read a 32-bit integral type
(not necessarily long or unsigned long, which can be larger than 32 bits). That,
in turn, probably means that <CODE>linear_congruential</CODE>, for example,
shouldn't be instantiated with a type larger than 32 bits in portable code.
(That, in turn, means that I can do the computation with a 64 bit int, and
not have to worry about overflows)</P>

<P>The generators that use floating point types (instantiations of
<CODE>subtract_with_carry_01</CODE>) specify the number of bits of precision
that result from applying the seed. Assuming a binary floating point representation,
that precision will be maintained as new values are generated. I haven't read
the C99 specification carefully, but it looks to me like it requires 10 decimal
digits in the mantissa of a double and a long double, so this is the upper
limit on the precision of portable floating point representations. This, in
turn, means that portable instantiations of <CODE>subtract_with_carry_01</CODE>
will use less than 32 bits of precision, So one 32-bit unsigned value can hold
one value from the state.</P>

<P>So, should the basic principle be that states are streamable as a
generator-determined number of implementation-defined unsigned integral
values (at least 32 bits wide)?</P>

<P><I>Marc Paterno says:</I> I think that Pete's explanation of the problem
and his suggestion are both good, and I agree with the basic principle
he proposes. To make sure I'm agreeing with what I think I'm agreeing with:</P>

<BLOCKQUOTE>Engines states should be streamable as a generator-determined number of
unsigned long values, as long as the implementation doesn't count on more
than 32 bits in the unsigned long values.</BLOCKQUOTE>

<P><I>Pete Becker says:</I> Yes, that's what I'm thinking.</P>

<P>Let me add this to the mix: we currently have a template member function named
<CODE>seed</CODE> that takes two iterators that point to a range of 32-bit unsigned values.
When saving its state, the generator should stream out a set of values that,
if passed as a range to <CODE>seed</CODE>, would recreate the current state. Then the
stream extractor simply does this (pardon my informality):</P>

<PRE>    basic_istream& operator&gt;&gt;(basic_istream& istr, engine& eng)
    {
    istream_iterator&lt;unsigned long&gt; begin(istr);
    istream_iterator&lt;unsigned long&gt; end();
    eng.seed(begin, end);
    return istr;
    }</PRE>

<P>That way all the constructors, all the <CODE>seed</CODE> functions, and the
stream extractor go through a single function, <CODE>seed(InIt&amp;, InIt)</CODE>.
Now all we have to do is properly describe the behavior of that function.</P>

<P><I>Pete Becker says:</I> In fact, since algorithms for distributions
aren't specified by the standard, it isn't possible to portably save and
restore the state of a distribution. I agree that portability doesn't seem to
be necessary -- reset, in conjunction with saving and restoring the
state of the engine, should suffice. Which raises the question of whether
saving and restoring the state of a distribution ought to be supported
at all (the proposal does provide for this).</P>

<P><I>Marc Paterno says:</I> Previously, we presented the reasons we believe
that portable saving and restoration of an engine's logical state is important.
We do not believe that *portable* saving and restoring of a distribution's state
has the same importance, and we also believe that the cost of such a
requirement would be too high.</P>

<P>However, we believe there are good reasons to keep the ability to save
and restore the state of a distribution, *without* requiring the saved
state be portable. Two of the four reasons we raised for the
portable saving and restoration of an engine's logical state are
closely related to reasons for requiring the saving and restoring of
state for distributions:</P>

<P>One of the reasons for saving state is the checkpointing of
long-running calculations. For this, saving binary state is
sufficient, and portability is not an issue.</P>

<P>A second reason for saving the state is to allow for reproducibility
of results. In order to verify, explore and extend simulation results,
researchers require the ability to reproduce, from a given checkpoint,
the stream of random numbers the original simulation relied upon. Even
though portable reproducibility will not be guaranteed, the feature is
still valuable. Vendors who provide a library that allows portability
across different hardware types may obtain an advantage here.</P>

<P>So, we would like to retain the requirement that the user be able to
save and restore the state of a distribution, but that we not impose
the additional requirement that the saved state be portable.</P>

<P><I>Pete Becker says:</I> I agree. I realized it after I posted my other message.</P>

<P><B>Proposed Resolution:</B></P>

<P><I>Need words to describe streaming of generators</I></P>

<HR>
</BODY>
</HTML>
