Topic: Conveniently generating random numbers with TR1 random
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Wed, 7 Nov 2007 01:01:59 GMT Raw View
jkherciueh@gmx.net wrote:
> Andrei Alexandrescu (See Website For Email wrote:
>
>> Walter E Brown wrote:
>>> On 2007-11-03 11:10 PM, jkherciueh@gmx.net wrote:
>>> > Andrei Alexandrescu (See Website For Email) wrote:
>>> > Those do no longer exist. The corresponding forms would be:
>>> >
>>> > a) uniform_int_distribution<int>(a,b)(gen)
>>> > b) uniform_int_distribution<int>(0,0)
>>> > ( gen, uniform_int_distribution<int>::param_type(a,b) )
>>>
>>> Yes, this is correct according to the latest Working Draft for C++0X.
>>>
>>> >
>>> > However, I think the intended way of using it is more like this:
>>> >
>>> > typedef uniform_int_distribution<int>::param_type range;
>>> >
>>> > uniform_int_distribution<int> u_int_d;
>>> >
>>> > c) u_int_d( gen, range(a,b) ); // reuse the same object!
>>>
>>> Yes, this is the intended way to use this two-argument function call
>>> operator. However, we believe that the single-argument function call
>>> operator will be used far more often in most programs.
>> I have to admit that right now I'm thoroughly confused about param_type,
>> and actually poring through all of its occurrences in the draft C++0X
>> spec does not help. I applied the following procedure:
>>
>> 1. Search N2461 for "param_type"
>>
>> 2. Read the vicinity of every occurrence.
>>
>> No avail whatsoever. (I am assuming that N2461 is self-contained;
>> otherwise, my point is moot.) Then I repeated the same procedure for
>> "param(", thinking that the homonym function is explained somewhere. I
>> did find an explanation in table 107 on page 855:
>>
>> Expression: u(e)
>> Type: T
>> Pre-post condition:
>> With p = u.param(), the sequence amortized
>> of numbers returned by successive constant number
>> invocations with the same object e of invocations of
>> is randomly distributed according e
>> to the associated p(z | {p}) or
>> P(zi | {p}) function.
>>
>> That's awfully little to go by in deducing what param_type and the
>> param() functions are about. I vaguely realise from having read past
>> documents that the parameter parameterizes the distribution, e.g. for a
>> Gaussian distribution the parameters would be \Sigma and \mu. Is that
>> correct?
>
>>From the outside, yes. But there is more than meets the eye: Many algorithms
> in generating non-uniform random numbers have a set-up phase and a phase
> for generating numbers when the parameters do not change. To take advantage
> of this one can put the set-up part of the algorithm within the constructor
> of the param_type object and store the precomputed data there. E.g., the
> algorithm for the Gamma distribution by Marsaglia and Tsang (Transactions
> in Math. Software, 26 (2000) 363-372) uses the coefficients
>
> d = a - 1/3
> c = 1/9d
>
> Instead of recomputing these in every call, one can just store them in the
> parameter object.
>
> This trick even extends to algorithms where there is dynamic data to be
> passed from one call of the RNG to the next.
Ok, so what you're saying is that param_type for
uniform_int_distribution is actually a pair of two integers (a and b)?
That would finally clarify things for me. I thought it's just one int.
>> Don't get me wrong in criticizing the library; by and large, I think
>> it's the best random number library design of all, by a mile. If I were
>> a random number, I'd think I died and went to heaven. Yet, I find it a
>> bit of a letdown that the new random library has all this great breadth
>> and depth, but in my humble opinion it hasn't really dotted the last
>> "i"s. Any complex library should be taken back to the simplest tasks
>> it's supposed to fulfill and checked if it makes them easy enough.
>
> I tend to agree with you on this one. However, Joe Coder is probably used to
> using rand() anyway; and it will be hard to convince him to look elsewhere.
You are strengthening my point. All the more reason to not alienate Joe
even more. Right now it looks to me like one has to be an expert in the
generation of random numbers just to get one.
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Wed, 7 Nov 2007 15:53:52 GMT Raw View
Walter E Brown wrote:
> On 2007-11-05 11:14 PM, Andrei Alexandrescu (See Website For Email) wrote:
> > Don't get me wrong in criticizing the library; by and large, I think
> > it's the best random number library design of all, by a mile. If I were
> > a random number, I'd think I died and went to heaven. Yet, I find it a
> > bit of a letdown that the new random library has all this great breadth
> > and depth, but in my humble opinion it hasn't really dotted the last
> > "i"s. Any complex library should be taken back to the simplest tasks
> > it's supposed to fulfill and checked if it makes them easy enough.
>
> Thank you for the kind words regarding this design.
>
> Alas, it is well known that Standards documents are rarely, if ever,
> useful as tutorials. The problem with trying to decide what might be
> best for Joe Coder is that there's no way to decide. Sometimes he wants
> speed of performance, sometimes he wants to minimize size, sometimes he
> wants the best quality of randomness (which itself can be measured in
> several different ways). No one engine is uniformly best on all counts,
> but each of the predefined engines (the typedefs in 26.4.5
> [rand.predef]) in the Standard has been recognized as "best" according
> to some of these criteria.
Oh, I so strongly disagree with that. It essentially ignores 80% of the
user base, if not more. But first let me clear up a possible
misunderstanding. What you say is correct - that different people have
different needs, and as such it's good to have something for each. But
it would be a fallacy to think that a default choice prevents people
with specific needs make a different choice. So what you said does not
counter what I said in the least.
To give you an example, I have this task with which many might be
familiar: initialize the weights of a neural network with random real
numbers with a Gaussian distribution of certain parameters. So in my
code I'll make use of the normal_distribution class, which is nice
because I actively want a normal distribution (so the name is highly
evocative), and, ahem... mt19937! What in the world does mt19937 have
with what I have to do? Why do I have to understand the minutiae about
the tradeoffs involved in random number generation for a task that has
zero relevance to the size and the time consumed by my application? What
does it evoke to a colleague reading my code, who does not know anything
about the Mersenne Twister of period 2 ** 19337?
What many people want is a reasonable (not best!) random number
generator, that's not too slow, not too bulky, not too predictable - one
that __gets the job done__. Right now the standard library random
library, for all of its stamina, fails to deliver on that. Instead, it
turns the problem into a Seinfeldesque conversation:
Joe Coder: "A Coke, please."
Stdlib: "What size?"
Joe: "Ionno... medium I guess."
Stdlib: "Old medium or new medium? Because what was medium is now small,
and what was large is now medium."
Joe: "Um... well, new medium."
Stdlib: "Sweetened with sugar, sucrose, or sucralose? Latest research
suggests that sugar damages teeth, lowers immunity, and favors fat
deposits by increasing insuline level in the blood; sucrose is allegedly
correlated with certain cancer risk factors; and sucralose has not been
proven good or bad yet, so we're kind of waiting on that."
Joe: "I don't really know... default? Something that has historically
worked the best?"
Stdlib: "That would be honey, but we don't have Coke with honey."
Joe: "You know what, forget the Coke. Just give me a glass of water."
Stdlib: "Tap, filtered, Evian, or Perrier?"
You got my drift :o).
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: wb@fnal.gov (Walter E Brown)
Date: Thu, 8 Nov 2007 20:48:44 GMT Raw View
On 2007-11-07 9:53 AM, Andrei Alexandrescu (See Website For Email) wrote:
> Walter E Brown wrote:
>> On 2007-11-05 11:14 PM, Andrei Alexandrescu (See Website For Email)
>> wrote:
>> > Don't get me wrong in criticizing the library; by and large, I think
>> > it's the best random number library design of all, by a mile. If I
>> were
>> > a random number, I'd think I died and went to heaven. Yet, I find
it a
>> > bit of a letdown that the new random library has all this great
>> breadth
>> > and depth, but in my humble opinion it hasn't really dotted the last
>> > "i"s. Any complex library should be taken back to the simplest tasks
>> > it's supposed to fulfill and checked if it makes them easy enough.
>>
>> Thank you for the kind words regarding this design.
>>
>> Alas, it is well known that Standards documents are rarely, if ever,
>> useful as tutorials. The problem with trying to decide what might be
>> best for Joe Coder is that there's no way to decide. Sometimes he
>> wants speed of performance, sometimes he wants to minimize size,
>> sometimes he wants the best quality of randomness (which itself can be
>> measured in several different ways). No one engine is uniformly best
>> on all counts, but each of the predefined engines (the typedefs in
>> 26.4.5 [rand.predef]) in the Standard has been recognized as "best"
>> according to some of these criteria.
>
> Oh, I so strongly disagree with that. It essentially ignores 80% of the
> user base, if not more. But first let me clear up a possible
> misunderstanding. What you say is correct - that different people have
> different needs, and as such it's good to have something for each. But
> it would be a fallacy to think that a default choice prevents people
> with specific needs make a different choice. So what you said does not
> counter what I said in the least.
>
> To give you an example, I have this task with which many might be
> familiar: initialize the weights of a neural network with random real
> numbers with a Gaussian distribution of certain parameters. So in my
> code I'll make use of the normal_distribution class, which is nice
> because I actively want a normal distribution (so the name is highly
> evocative), and, ahem... mt19937! What in the world does mt19937 have
> with what I have to do? Why do I have to understand the minutiae about
> the tradeoffs involved in random number generation for a task that has
> zero relevance to the size and the time consumed by my application? What
> does it evoke to a colleague reading my code, who does not know anything
> about the Mersenne Twister of period 2 ** 19337?
>
> What many people want is a reasonable (not best!) random number
> generator, that's not too slow, not too bulky, not too predictable - one
> that __gets the job done__. Right now the standard library random
> library, for all of its stamina, fails to deliver on that. Instead, it
> turns the problem into a Seinfeldesque conversation:
>
> Joe Coder: "A Coke, please."
> Stdlib: "What size?"
> Joe: "Ionno... medium I guess."
> Stdlib: "Old medium or new medium? Because what was medium is now small,
> and what was large is now medium."
> Joe: "Um... well, new medium."
> Stdlib: "Sweetened with sugar, sucrose, or sucralose? Latest research
> suggests that sugar damages teeth, lowers immunity, and favors fat
> deposits by increasing insuline level in the blood; sucrose is allegedly
> correlated with certain cancer risk factors; and sucralose has not been
> proven good or bad yet, so we're kind of waiting on that."
> Joe: "I don't really know... default? Something that has historically
> worked the best?"
> Stdlib: "That would be honey, but we don't have Coke with honey."
> Joe: "You know what, forget the Coke. Just give me a glass of water."
> Stdlib: "Tap, filtered, Evian, or Perrier?"
>
> You got my drift :o).
Your disagreement seems based on a misunderstanding. I wrote "that
there's no way to decide [because n]o one engine is uniformly best on
all counts...." but you seem to have taken that as suggesting that we
are unsympathetic to your view and unwilling to consider it further.
Both would be incorrect interpretations.
(BTW, the mocking tone of your "Seinfeldesque conversation" does not at
all help to advance your case. Let's try to make some progress, without
the barbs from now on.)
We still believe that the Standard should not dictate which URNG is
"best" for Joe Coder. However, that does not preclude an
implementation-defined typedef for some URNG that the implementer
believes is best for a given platform and implementation.
Therefore, we would be willing to propose to WG21 the addition of a new
typedef along those lines. There are a few technical issues to decide:
1) Should the typedef be restricted to aliasing one of the predefined
engine types in [rand.predef]?
2) If not, should the entity aliasing the typedef be required to meet
only the requirements of a Uniform Random Number Generator, or should it
be required to meet the added requirements of Random Number Engine as
well? (In brief, the latter would provide additional constructors, as
well as I/O capability for the entity.)
3) And a classical bicycle shed issue: what name would we like for this
typedef?
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Thu, 8 Nov 2007 22:43:02 GMT Raw View
Walter E Brown wrote:
> Your disagreement seems based on a misunderstanding. I wrote "that
> there's no way to decide [because n]o one engine is uniformly best on
> all counts...." but you seem to have taken that as suggesting that we
> are unsympathetic to your view and unwilling to consider it further.
> Both would be incorrect interpretations.
Sounds great.
> (BTW, the mocking tone of your "Seinfeldesque conversation" does not at
> all help to advance your case. Let's try to make some progress, without
> the barbs from now on.)
Just being my usual humorous self. I understand that it might not seem
as humorous to someone who's put many hours into defining the library.
But there's really no reason to take it any other way.
> We still believe that the Standard should not dictate which URNG is
> "best" for Joe Coder. However, that does not preclude an
> implementation-defined typedef for some URNG that the implementer
> believes is best for a given platform and implementation.
>
> Therefore, we would be willing to propose to WG21 the addition of a new
> typedef along those lines. There are a few technical issues to decide:
>
> 1) Should the typedef be restricted to aliasing one of the predefined
> engine types in [rand.predef]?
Probably not, as that would stifle progress. I mean, think that this
random library was standardized the day before the Mersenne Twister
paper was published. That would have rendered it automatically obsolete.
Similarly, what if a couple of years from now, somebody invents a random
generator that works way better and is way faster than all others (or at
least finds some parameters for MT that are better than the defaults).
In that case, it would be nice if the standard had a way to allow
implementers to define that generator as being the most appropriate.
> 2) If not, should the entity aliasing the typedef be required to meet
> only the requirements of a Uniform Random Number Generator, or should it
> be required to meet the added requirements of Random Number Engine as
> well? (In brief, the latter would provide additional constructors, as
> well as I/O capability for the entity.)
Probably the latter; the extra requirements are quite reasonable and are
not likely to put much burden on the implementors.
> 3) And a classical bicycle shed issue: what name would we like for this
> typedef?
Since you asked... Something that describes the task being done would be
best, so I'm biased towards a name with the "random" word in it. I also
favor short names, so the algorithm of my preferences inexorably fixes
me in the "random" optimal point :o). But for consistency with the rest
of the library, "random_generator" would be another possibility. I'm
sure, however, that many will find the presence of "default" necessary,
too, and so on...
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: wb@fnal.gov (Walter E Brown)
Date: Thu, 1 Nov 2007 15:01:01 GMT Raw View
On 2007-10-31 12:30 PM, Andrei Alexandrescu (See Website For Email) wrote:
> Walter E Brown wrote:
>> On 2007-10-29 1:00 PM, Andrei Alexandrescu (See Website For Email)
>> wrote:
>>> Hello,
>>>
>>> I've studied Jens Maurer's TR1 random numbers
>>> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html).
>>> Very nicely done! I have a question-comment.
>>
>> Thank you. My colleagues at Fermilab and I collaborated with Jens at
>> the time he was preparing this proposal. As another poster in this
>> thread has pointed out, this portion of the standard library has
>> undergone substantial evolution and refinement since the early TR1
>> version to which you refer above.
>>
>> Because your "question-comment" concerns itself with certain details
>> of what we consider a superseded version, I have snipped it from this
>> posting.
>>
>> I would respectfully recommend that, at your convenience, you look at
>> section [rand] (26.4) of committee paper N2461, the latest Working
>> Draft for C++0X, published just this week. You might also want to
>> review the latest description of the random-shuffle algorithm in
>> section [alg.random.shuffle] (25.2.12).
>
> Thanks for the flowery language :o). An URL would have been equally
> appreciated. Are you, for example, referring to the N2461 available from
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007 ?
Sorry if the language seemed "flowery"; as a non-native speaker of
English, that's simply the way I normally speak and write, and
especially so when it's in a public forum.
Sorry again re the lack of URLs. I didn't bother with them because:
a) I didn't have enough of them handy;
b) the references were pasted from a document that I did have handy;
c) a previous poster in the same thread had already referenced N2461;
d) since you are a recognized C++ expert, I assumed that you knew
where Committee documents were made publicly available.
For the record, yes, you seem to have found the correct N2461.
>
> [snip]
>> After you've had a chance to bring yourself up to date, we would be
>> pleased to have your further comments.
>
> While I'm thoroughly impressed by you walking me through the mentioned
> bibliography, if what I wanted was to absorb all of the minutiae of the
> random numbers, probably I wouldn't even have written here. What I was
> hoping was a simple answer to a simple question from someone who already
> knows that information. Sure if someone asked me a simple question about
> machine learning I wouldn't send her to read everything from Vapnik's
> 1974 paper onward.
No one here is or was trying to impress you; we were merely conveying
information. What I tried to convey in particular is that TR1's version
is no longer current, that many aspects of the random number facility
have been improved, and that your questions might be better answered if
phrased in terms of the interface now found in the Working Draft.
I see that you've separately now posted a question phrased in terms of
the intermediate document N2032, but I don't know why of all the
references I provided you would choose that one, clearly labeled
"version 2" and equally clearly succeeded by a "version 3" and a
"version 4".
More importantly, your question seems to misconstrue the nature of
"param_type" in the distributions. In particular, you wrote: "I see
with chagrin that the operator()(UniformRandomNumberGenerator& urng,
const param_type& parm) is still there. I don't understand why. The nice
thing is that the function is constrained to a specific integral type
param_type."
(1) I don't know why you believe that param_type is an integral type.
There's no such requirement.
(2) As stated in N1933, param_type and related functions "provide a
uniform interface so that distribution parameters can be manipulated
generically: it now becomes possible to write code that is independent
of any specific distribution."
And finally, let me see if I understand your basic concern about the
interface to a distribution. Is it that you believe that the member
templates of the following form are superfluous?
template<class URNG>
result_type
..._distribution::operator()(URNG&, param_type const &)
If so, please let me know and I will be very happy to address that
specific issue.
Best,
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@erdani.org>
Date: Sat, 3 Nov 2007 17:19:52 CST Raw View
Walter E Brown wrote:
[snip]
Thanks for the excellent information.
> I see that you've separately now posted a question phrased in terms of
> the intermediate document N2032, but I don't know why of all the
> references I provided you would choose that one, clearly labeled
> "version 2" and equally clearly succeeded by a "version 3" and a
> "version 4".
>
> More importantly, your question seems to misconstrue the nature of
> "param_type" in the distributions. In particular, you wrote: "I see
> with chagrin that the operator()(UniformRandomNumberGenerator& urng,
> const param_type& parm) is still there. I don't understand why. The nice
> thing is that the function is constrained to a specific integral type
> param_type."
>
> (1) I don't know why you believe that param_type is an integral type.
> There's no such requirement.
>
> (2) As stated in N1933, param_type and related functions "provide a
> uniform interface so that distribution parameters can be manipulated
> generically: it now becomes possible to write code that is independent
> of any specific distribution."
Ok, I understand.
> And finally, let me see if I understand your basic concern about the
> interface to a distribution. Is it that you believe that the member
> templates of the following form are superfluous?
> template<class URNG>
> result_type
> ..._distribution::operator()(URNG&, param_type const &)
> If so, please let me know and I will be very happy to address that
> specific issue.
Yes, that's the root of my question. More specifically, I'm not sure
what method to use when generating integers in a range [a, b]. My
understanding is that I could go two routes:
a) Call uniform_int<int>(a, b)(gen)
b) Call a + uniform_int<int>(whatever, whatever)(gen, b + 1)
Why are there two ways, and what are the tradeoffs guiding the choice of
using one of them?
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: jkherciueh@gmx.net
Date: Sun, 4 Nov 2007 04:10:13 GMT Raw View
Andrei Alexandrescu (See Website For Email) wrote:
> Walter E Brown wrote:
> [snip]
>
> Thanks for the excellent information.
>
>> I see that you've separately now posted a question phrased in terms of
>> the intermediate document N2032, but I don't know why of all the
>> references I provided you would choose that one, clearly labeled
>> "version 2" and equally clearly succeeded by a "version 3" and a
>> "version 4".
>>
>> More importantly, your question seems to misconstrue the nature of
>> "param_type" in the distributions. In particular, you wrote: "I see
>> with chagrin that the operator()(UniformRandomNumberGenerator& urng,
>> const param_type& parm) is still there. I don't understand why. The nice
>> thing is that the function is constrained to a specific integral type
>> param_type."
>>
>> (1) I don't know why you believe that param_type is an integral type.
>> There's no such requirement.
>>
>> (2) As stated in N1933, param_type and related functions "provide a
>> uniform interface so that distribution parameters can be manipulated
>> generically: it now becomes possible to write code that is independent
>> of any specific distribution."
>
> Ok, I understand.
>
>> And finally, let me see if I understand your basic concern about the
>> interface to a distribution. Is it that you believe that the member
>> templates of the following form are superfluous?
>> template<class URNG>
>> result_type
>> ..._distribution::operator()(URNG&, param_type const &)
>> If so, please let me know and I will be very happy to address that
>> specific issue.
>
> Yes, that's the root of my question.
One observation is that a distribution object can maintain its own buffer of
entropy. For instance, if you have a distribution that generates 8bit chars
and you call it with an engine that provides 32 random bits (via an
unsigned long), the your distribution object may have a little buffer for
later use, i.e., some calls
dist( urng )
may actually not call the RNG. One effect of (a) allowing the distribution
parameters to change and (b) having the meber
..._distribution::operator()(URNG&, param_type const &)
is that this pool of entropy can be reused. E.g., when you need to generate
random ints on smaller and smaller ranges, it could be wastefull to
construct a new distribution object ever time since you throw away random
bits.
> More specifically, I'm not sure
> what method to use when generating integers in a range [a, b]. My
> understanding is that I could go two routes:
>
> a) Call uniform_int<int>(a, b)(gen)
>
> b) Call a + uniform_int<int>(whatever, whatever)(gen, b + 1)
>
> Why are there two ways, and what are the tradeoffs guiding the choice of
> using one of them?
Those do no longer exist. The corresponding forms would be:
a) uniform_int_distribution<int>(a,b)(gen)
b) uniform_int_distribution<int>(0,0)
( gen, uniform_int_distribution<int>::param_type(a,b) )
However, It think the intended way of using it is more like this:
typedef uniform_int_distribution<int>::param_type range;
uniform_int_distribution<int> u_int_d;
c) u_int_d( gen, range(a,b) ); // reuse the same object!
Best
Kai-Uwe Bux
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 5 Nov 2007 18:01:50 GMT Raw View
jkherciueh@gmx.net ha scritto:
> Those do no longer exist. The corresponding forms would be:
>
> a) uniform_int_distribution<int>(a,b)(gen)
> b) uniform_int_distribution<int>(0,0)
> ( gen, uniform_int_distribution<int>::param_type(a,b) )
>
> However, It think the intended way of using it is more like this:
>
> typedef uniform_int_distribution<int>::param_type range;
>
> uniform_int_distribution<int> u_int_d;
>
> c) u_int_d( gen, range(a,b) ); // reuse the same object!
>
It seems to me that param_type is seriously underspecified. The current
wording leaves too much to the implementation, IMHO. In particular:
1) what is the signature of the param_type constructor? For example, the
uniform_int_distribution class has one constructor with two parameters,
and both of them have default values. Therefore, I can expect (although
it's never said clearly) that the uniform_int_distribution::param_type
constructor has exactly two parameters, but do they have default values
too? In other words, will it be possible to write:
typedef uniform_int_distribution<int>::param_type range;
range r1; // a = 0, b = numeric_limits<int>::max()
range r2(10); // a = 10, b = numeric_limits<int>::max()
2) is the param_type constructor explicit? That would make a big
difference, for example with bernoulli_distribution whose only one
parameter is a double. In particular, will I be able to write this:
bernoulli_distribution bd;
bd(gen, 1.0);
instead of the more verbose:
bernoulli_distribution bd;
bd(gen, bernoulli_distribution::param_type(1.0));
?
3) is param_type copy-constructible? Well, I guess so, but it's not
clear from current wording. This may be important in case I need to
store distribution parameters inside a container.
4) what is the complexity of copying a param_type? This is not trivial
for the sampling distributions, whose param_type are likely to hold one
or more std::vectors.
5) is param_type a "literal type" (see 3.9/11), where it makes sense? It
would be very nice to have that!
I suggest we add some requirements about that. In particular (using
terminology from 26.4.1.5 [rand.req.dist]):
A) whenever
X u(/parameter list/);
is well formed,
P p(/parameter list/);
shall also be well-formed and X(p) shall create a distribution whose
behavior is indistinguishable from u [Note: this may require P to be of
class type, because a default constructor performing some non-trivial
initialization may be needed. -end note]
B) P shall be CopyConstructible. If all constructors of X not involving
P take parameters of literal type, P shall be of literal type and all
its constructors shall be declared constexpr.
C) A note to [rand.dist.samp.discrete] and [rand.dist.samp.pconst] shall
be added: "The type param_type has a copy constructor with linear
complexity in n and a move constructor with constant complexity."
D) Consider adding rvalue overload of the constructor and param() method
that takes const param_type&, at least for all distributions in
[rand.dist.samp].
D) Add ither one of these requirements:
P's constructors shall be declared explicit
or
P's constructors shall not be declared explicit
I expect the "shall not" version to raise a lot of resistance, yet it's
my favorite.
Just my opinion,
Ganesh
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: wb@fnal.gov (Walter E Brown)
Date: Mon, 5 Nov 2007 22:31:43 GMT Raw View
On 2007-11-03 11:10 PM, jkherciueh@gmx.net wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>> Walter E Brown wrote:
>> [snip]
>>
>> Thanks for the excellent information.
You're welcome.
>>
>>> I see that you've separately now posted a question phrased in terms of
>>> the intermediate document N2032, but I don't know why of all the
>>> references I provided you would choose that one, clearly labeled
>>> "version 2" and equally clearly succeeded by a "version 3" and a
>>> "version 4".
>>>
>>> More importantly, your question seems to misconstrue the nature of
>>> "param_type" in the distributions. In particular, you wrote: "I see
>>> with chagrin that the operator()(UniformRandomNumberGenerator& urng,
>>> const param_type& parm) is still there. I don't understand why. The
nice
>>> thing is that the function is constrained to a specific integral type
>>> param_type."
>>>
>>> (1) I don't know why you believe that param_type is an integral type.
>>> There's no such requirement.
>>>
>>> (2) As stated in N1933, param_type and related functions "provide a
>>> uniform interface so that distribution parameters can be manipulated
>>> generically: it now becomes possible to write code that is independent
>>> of any specific distribution."
>> Ok, I understand.
>>
>>> And finally, let me see if I understand your basic concern about the
>>> interface to a distribution. Is it that you believe that the member
>>> templates of the following form are superfluous?
>>> template<class URNG>
>>> result_type
>>> ..._distribution::operator()(URNG&, param_type const &)
>>> If so, please let me know and I will be very happy to address that
>>> specific issue.
>> Yes, that's the root of my question.
>
> One observation is that a distribution object can maintain its own
buffer of
> entropy. For instance, if you have a distribution that generates 8bit
chars
> and you call it with an engine that provides 32 random bits (via an
> unsigned long), the your distribution object may have a little buffer for
> later use, i.e., some calls
>
> dist( urng )
>
> may actually not call the RNG. One effect of (a) allowing the
distribution
> parameters to change and (b) having the member
>
> ..._distribution::operator()(URNG&, param_type const &)
>
> is that this pool of entropy can be reused. E.g., when you need to
generate
> random ints on smaller and smaller ranges, it could be wasteful to
> construct a new distribution object every time since you throw away
random
> bits.
>
Yes. As one specific example, the well-known Box-Mueller algorithm for
a normal distribution works in precisely this way.
>> More specifically, I'm not sure
>> what method to use when generating integers in a range [a, b]. My
>> understanding is that I could go two routes:
>>
>> a) Call uniform_int<int>(a, b)(gen)
>>
>> b) Call a + uniform_int<int>(whatever, whatever)(gen, b + 1)
>>
>> Why are there two ways, and what are the tradeoffs guiding the choice of
>> using one of them?
>
> Those do no longer exist. The corresponding forms would be:
>
> a) uniform_int_distribution<int>(a,b)(gen)
> b) uniform_int_distribution<int>(0,0)
> ( gen, uniform_int_distribution<int>::param_type(a,b) )
Yes, this is correct according to the latest Working Draft for C++0X.
>
> However, I think the intended way of using it is more like this:
>
> typedef uniform_int_distribution<int>::param_type range;
>
> uniform_int_distribution<int> u_int_d;
>
> c) u_int_d( gen, range(a,b) ); // reuse the same object!
Yes, this is the intended way to use this two-argument function call
operator. However, we believe that the single-argument function call
operator will be used far more often in most programs.
Best,
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: wb@fnal.gov (Walter E Brown)
Date: Tue, 6 Nov 2007 00:21:19 GMT Raw View
On 2007-11-05 12:01 PM, Alberto Ganesh Barbati wrote:
> jkherciueh@gmx.net ha scritto:
>> Those do no longer exist. The corresponding forms would be:
>>
>> a) uniform_int_distribution<int>(a,b)(gen)
>> b) uniform_int_distribution<int>(0,0)
>> ( gen, uniform_int_distribution<int>::param_type(a,b) )
>>
>> However, It think the intended way of using it is more like this:
>>
>> typedef uniform_int_distribution<int>::param_type range;
>>
>> uniform_int_distribution<int> u_int_d;
>>
>> c) u_int_d( gen, range(a,b) ); // reuse the same object!
>>
>
> It seems to me that param_type is seriously underspecified. The current
> wording leaves too much to the implementation, IMHO. In particular:
>
> 1) what is the signature of the param_type constructor? For example, the
> uniform_int_distribution class has one constructor with two parameters,
> and both of them have default values. Therefore, I can expect (although
> it's never said clearly) that the uniform_int_distribution::param_type
> constructor has exactly two parameters, but do they have default values
> too? In other words, will it be possible to write:
>
> typedef uniform_int_distribution<int>::param_type range;
> range r1; // a = 0, b = numeric_limits<int>::max()
> range r2(10); // a = 10, b = numeric_limits<int>::max()
According to N2461 (the latest Working Draft for C++0X), clause
26.4.1.5/8, "For each of the constructors of [the random number
distribution] X taking arguments corresponding to parameters of the
distribution, [the param_type] P shall have a corresponding constructor
subject to the same requirements and taking arguments identical in
number, type, and default values."
Therefore, we believe this matter of defaults is sufficiently well
specified, and the above example should work as intended.
>
> 2) is the param_type constructor explicit? That would make a big
> difference, for example with bernoulli_distribution whose only one
> parameter is a double. In particular, will I be able to write this:
>
> bernoulli_distribution bd;
> bd(gen, 1.0);
>
> instead of the more verbose:
>
> bernoulli_distribution bd;
> bd(gen, bernoulli_distribution::param_type(1.0));
>
> ?
Based on the phrase "subject to the same requirements" (see the
paragraph quoted above), each param_type c'tor is explicit iff its
corresponding distribution c'tor is explicit.
If you feel this is insufficiently clear, or if you feel that it would
be better if param_type c'tors were never explicit, you are welcome to
submit a defect report about this.
>
> 3) is param_type copy-constructible? Well, I guess so, but it's not
> clear from current wording. This may be important in case I need to
> store distribution parameters inside a container.
According to N2461 (the latest Working Draft for C++0X), clause
26.4.1.5/7, "[The param_type] P shall satisfy the requirements of
CopyConstructible, Assignable, and EqualityComparable."
Therefore, we believe this matter of copy construction is sufficiently
well specified.
>
> 4) what is the complexity of copying a param_type? This is not trivial
> for the sampling distributions, whose param_type are likely to hold one
> or more std::vectors.
We believe this is best left as a quality-of-implementation matter.
>
> 5) is param_type a "literal type" (see 3.9/11), where it makes sense? It
> would be very nice to have that!
>
> I suggest we add some requirements about that. In particular (using
> terminology from 26.4.1.5 [rand.req.dist]):
>
> A) whenever
> X u(/parameter list/);
> is well formed,
> P p(/parameter list/);
> shall also be well-formed and X(p) shall create a distribution whose
> behavior is indistinguishable from u [Note: this may require P to be of
> class type, because a default constructor performing some non-trivial
> initialization may be needed. -end note]
>
> B) P shall be CopyConstructible. If all constructors of X not involving
> P take parameters of literal type, P shall be of literal type and all
> its constructors shall be declared constexpr.
>
> C) A note to [rand.dist.samp.discrete] and [rand.dist.samp.pconst] shall
> be added: "The type param_type has a copy constructor with linear
> complexity in n and a move constructor with constant complexity."
>
> D) Consider adding rvalue overload of the constructor and param() method
> that takes const param_type&, at least for all distributions in
> [rand.dist.samp].
>
> D) Add either one of these requirements:
>
> P's constructors shall be declared explicit
>
> or
>
> P's constructors shall not be declared explicit
>
> I expect the "shall not" version to raise a lot of resistance, yet it's
> my favorite.
The clause specifying the random number library was written before
literal types (and several other new language features) were voted into
the Working Draft for C++0X. It is the intent of the Library Working
Group to undertake a review of existing library features with an eye
toward taking advantage of these new language features where useful and
feasible. We will keep your suggestions in mind when undertaking that
review.
Best,
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Tue, 6 Nov 2007 05:14:37 GMT Raw View
Walter E Brown wrote:
> On 2007-11-03 11:10 PM, jkherciueh@gmx.net wrote:
> > Andrei Alexandrescu (See Website For Email) wrote:
> > Those do no longer exist. The corresponding forms would be:
> >
> > a) uniform_int_distribution<int>(a,b)(gen)
> > b) uniform_int_distribution<int>(0,0)
> > ( gen, uniform_int_distribution<int>::param_type(a,b) )
>
> Yes, this is correct according to the latest Working Draft for C++0X.
>
> >
> > However, I think the intended way of using it is more like this:
> >
> > typedef uniform_int_distribution<int>::param_type range;
> >
> > uniform_int_distribution<int> u_int_d;
> >
> > c) u_int_d( gen, range(a,b) ); // reuse the same object!
>
> Yes, this is the intended way to use this two-argument function call
> operator. However, we believe that the single-argument function call
> operator will be used far more often in most programs.
I have to admit that right now I'm thoroughly confused about param_type,
and actually poring through all of its occurrences in the draft C++0X
spec does not help. I applied the following procedure:
1. Search N2461 for "param_type"
2. Read the vicinity of every occurrence.
No avail whatsoever. (I am assuming that N2461 is self-contained;
otherwise, my point is moot.) Then I repeated the same procedure for
"param(", thinking that the homonym function is explained somewhere. I
did find an explanation in table 107 on page 855:
Expression: u(e)
Type: T
Pre-post condition:
With p = u.param(), the sequence amortized
of numbers returned by successive constant number
invocations with the same object e of invocations of
is randomly distributed according e
to the associated p(z | {p}) or
P(zi | {p}) function.
That's awfully little to go by in deducing what param_type and the
param() functions are about. I vaguely realise from having read past
documents that the parameter parameterizes the distribution, e.g. for a
Gaussian distribution the parameters would be \Sigma and \mu. Is that
correct? If so, then it's unclear to me where it says that an integral
distribution has one parameter that's its range. I looked all over
uniform_int_distribution, it just doesn't say a thing.
A second issue I discovered while thinking of the random numbers library
is that there's no generator called "random". There are various
generators whose names tell _how_ the job is done, yet none that says
_what_ job is being done and offers to readily take up the task.
This might seem silly, but I think it's not. Think of Joe Coder trying
to generate some random numbers. Joe happily pulls his just-installed
C++0X's documentation, looks up random numbers, and sure enough, there's
plenty of stuff to play with. The problem is that Joe does not know or
care much about how random numbers are generated, so names like
"linear_congruential_engine", "mersenne_twister_engine", or
"hole_in_the_ground" are all just the same to him; he just wants to get
work done. So Joe finds himself with an embarrassment of riches:
1. Should he use minstd_rand0?
2. minstd_rand perhaps? (That "0" didn't look that good anyway.)
3. The ungainly-named mt19937?
4. The Latin-sounding, luminous and optimistic ranlux* variety? (Fiat Lux!)
.
10. Templatize the whole thing with the generator type and toss the
choice point elsewhere?
That's lots of choice, which is good if Joe's focus was Monte Carlo
simulation, hashing, cryptography, and the such, but really, all Joe is
trying here is to generate some plain vanilla random numbers.
So I suggest the standard library provides a typedef called "random" (or
"random_generator" etc.) for whatever the library implementation
believes is the most appropriate generator for the given platform. On
most platforms, probably:
typedef mt19937 random;
would do, and on a tight embedded system:
typedef minstd_rand random;
would be more appropriate.
Don't get me wrong in criticizing the library; by and large, I think
it's the best random number library design of all, by a mile. If I were
a random number, I'd think I died and went to heaven. Yet, I find it a
bit of a letdown that the new random library has all this great breadth
and depth, but in my humble opinion it hasn't really dotted the last
"i"s. Any complex library should be taken back to the simplest tasks
it's supposed to fulfill and checked if it makes them easy enough.
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: jkherciueh@gmx.net
Date: Tue, 6 Nov 2007 06:13:21 GMT Raw View
Andrei Alexandrescu (See Website For Email wrote:
> Walter E Brown wrote:
>> On 2007-11-03 11:10 PM, jkherciueh@gmx.net wrote:
>> > Andrei Alexandrescu (See Website For Email) wrote:
>> > Those do no longer exist. The corresponding forms would be:
>> >
>> > a) uniform_int_distribution<int>(a,b)(gen)
>> > b) uniform_int_distribution<int>(0,0)
>> > ( gen, uniform_int_distribution<int>::param_type(a,b) )
>>
>> Yes, this is correct according to the latest Working Draft for C++0X.
>>
>> >
>> > However, I think the intended way of using it is more like this:
>> >
>> > typedef uniform_int_distribution<int>::param_type range;
>> >
>> > uniform_int_distribution<int> u_int_d;
>> >
>> > c) u_int_d( gen, range(a,b) ); // reuse the same object!
>>
>> Yes, this is the intended way to use this two-argument function call
>> operator. However, we believe that the single-argument function call
>> operator will be used far more often in most programs.
>
> I have to admit that right now I'm thoroughly confused about param_type,
> and actually poring through all of its occurrences in the draft C++0X
> spec does not help. I applied the following procedure:
>
> 1. Search N2461 for "param_type"
>
> 2. Read the vicinity of every occurrence.
>
> No avail whatsoever. (I am assuming that N2461 is self-contained;
> otherwise, my point is moot.) Then I repeated the same procedure for
> "param(", thinking that the homonym function is explained somewhere. I
> did find an explanation in table 107 on page 855:
>
> Expression: u(e)
> Type: T
> Pre-post condition:
> With p = u.param(), the sequence amortized
> of numbers returned by successive constant number
> invocations with the same object e of invocations of
> is randomly distributed according e
> to the associated p(z | {p}) or
> P(zi | {p}) function.
>
> That's awfully little to go by in deducing what param_type and the
> param() functions are about. I vaguely realise from having read past
> documents that the parameter parameterizes the distribution, e.g. for a
> Gaussian distribution the parameters would be \Sigma and \mu. Is that
> correct?
>From the outside, yes. But there is more than meets the eye: Many algorithms
in generating non-uniform random numbers have a set-up phase and a phase
for generating numbers when the parameters do not change. To take advantage
of this one can put the set-up part of the algorithm within the constructor
of the param_type object and store the precomputed data there. E.g., the
algorithm for the Gamma distribution by Marsaglia and Tsang (Transactions
in Math. Software, 26 (2000) 363-372) uses the coefficients
d = a - 1/3
c = 1/9d
Instead of recomputing these in every call, one can just store them in the
parameter object.
This trick even extends to algorithms where there is dynamic data to be
passed from one call of the RNG to the next.
> If so, then it's unclear to me where it says that an integral
> distribution has one parameter that's its range. I looked all over
> uniform_int_distribution, it just doesn't say a thing.
That uniform_int_distribution::param_type does, at least, parameterize
intervals [a,b] follows from the requirements about how the constructors
interact. Also, note that uniform_int_distribution::param_type is required
to have methods a() and b() that return the bounds of the interval. This is
in [26.5.1.5/8]. That the values a and b stored in a param_type object have
the same meaning as the parameters for the constructor of
uniform_int_distribution is in the table:
X(p) Creates a distribution whose
behavior is indistinguishable from
that of a distribution newly
constructed directly from the
values used to construct p.
> A second issue I discovered while thinking of the random numbers library
> is that there's no generator called "random". There are various
> generators whose names tell _how_ the job is done, yet none that says
> _what_ job is being done and offers to readily take up the task.
>
> This might seem silly, but I think it's not. Think of Joe Coder trying
> to generate some random numbers. Joe happily pulls his just-installed
> C++0X's documentation, looks up random numbers, and sure enough, there's
> plenty of stuff to play with. The problem is that Joe does not know or
> care much about how random numbers are generated, so names like
> "linear_congruential_engine", "mersenne_twister_engine", or
> "hole_in_the_ground" are all just the same to him; he just wants to get
> work done. So Joe finds himself with an embarrassment of riches:
>
> 1. Should he use minstd_rand0?
>
> 2. minstd_rand perhaps? (That "0" didn't look that good anyway.)
>
> 3. The ungainly-named mt19937?
>
> 4. The Latin-sounding, luminous and optimistic ranlux* variety? (Fiat
> Lux!)
>
> .
>
> 10. Templatize the whole thing with the generator type and toss the
> choice point elsewhere?
>
> That's lots of choice, which is good if Joe's focus was Monte Carlo
> simulation, hashing, cryptography, and the such, but really, all Joe is
> trying here is to generate some plain vanilla random numbers.
>
> So I suggest the standard library provides a typedef called "random" (or
> "random_generator" etc.) for whatever the library implementation
> believes is the most appropriate generator for the given platform. On
> most platforms, probably:
>
> typedef mt19937 random;
>
> would do, and on a tight embedded system:
>
> typedef minstd_rand random;
>
> would be more appropriate.
>
> Don't get me wrong in criticizing the library; by and large, I think
> it's the best random number library design of all, by a mile. If I were
> a random number, I'd think I died and went to heaven. Yet, I find it a
> bit of a letdown that the new random library has all this great breadth
> and depth, but in my humble opinion it hasn't really dotted the last
> "i"s. Any complex library should be taken back to the simplest tasks
> it's supposed to fulfill and checked if it makes them easy enough.
I tend to agree with you on this one. However, Joe Coder is probably used to
using rand() anyway; and it will be hard to convince him to look elsewhere.
Best
Kai-Uwe Bux
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: jkherciueh@gmx.net
Date: Tue, 6 Nov 2007 15:59:42 GMT Raw View
Andrei Alexandrescu (See Website For Email wrote:
[snip]
> A second issue I discovered while thinking of the random numbers library
> is that there's no generator called "random". There are various
> generators whose names tell _how_ the job is done, yet none that says
> _what_ job is being done and offers to readily take up the task.
>
> This might seem silly, but I think it's not. Think of Joe Coder trying
> to generate some random numbers. Joe happily pulls his just-installed
> C++0X's documentation, looks up random numbers, and sure enough, there's
> plenty of stuff to play with. The problem is that Joe does not know or
> care much about how random numbers are generated, so names like
> "linear_congruential_engine", "mersenne_twister_engine", or
> "hole_in_the_ground" are all just the same to him; he just wants to get
> work done. So Joe finds himself with an embarrassment of riches:
>
> 1. Should he use minstd_rand0?
>
> 2. minstd_rand perhaps? (That "0" didn't look that good anyway.)
>
> 3. The ungainly-named mt19937?
>
> 4. The Latin-sounding, luminous and optimistic ranlux* variety? (Fiat
> Lux!)
>
> .
>
> 10. Templatize the whole thing with the generator type and toss the
> choice point elsewhere?
>
> That's lots of choice, which is good if Joe's focus was Monte Carlo
> simulation, hashing, cryptography, and the such, but really, all Joe is
> trying here is to generate some plain vanilla random numbers.
>
> So I suggest the standard library provides a typedef called "random" (or
> "random_generator" etc.) for whatever the library implementation
> believes is the most appropriate generator for the given platform. On
> most platforms, probably:
>
> typedef mt19937 random;
>
> would do, and on a tight embedded system:
>
> typedef minstd_rand random;
>
> would be more appropriate.
I am not so sure that a typedef to one of the RNGs is the most convenient
thing for Joe. What about a small, easy to use rng-object for picking an
index in a vector. Something small like this came to mind:
class random {
typedef uniform_int_distribution<unsigned long > uniform;
typedef typename uniform::param_type parameter;
uniform the_dist;
mt19937 the_urng; // implementation defined RNG
public:
random ( void )
: the_dist ()
, the_urng ( <some unpredictable seed, changing between calls> )
{}
random ( unsigned long seed )
: the_dist ()
, the_urng ( seed )
{}
unsigned long operator() ( void ) {
return ( the_dist( the_urng() ) );
}
unsigned long operator() ( unsigned long bound ) {
return ( the_dist( the_urng, parameter( 0, bound-1 ) ) );
}
};
The two constructors are for seeding (a) with a truly random value
(something better than using the current time) and (b) from a known value.
The two operator() methods take care of two common needs.
Best
Kai-Uwe Bux
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: Walter E Brown <wb@fnal.gov>
Date: Tue, 6 Nov 2007 14:29:22 CST Raw View
On 2007-11-05 11:14 PM, Andrei Alexandrescu (See Website For Email) wrote:
> Walter E Brown wrote:
>> On 2007-11-03 11:10 PM, jkherciueh@gmx.net wrote:
>> > Andrei Alexandrescu (See Website For Email) wrote:
>> > Those do no longer exist. The corresponding forms would be:
>> >
>> > a) uniform_int_distribution<int>(a,b)(gen)
>> > b) uniform_int_distribution<int>(0,0)
>> > ( gen, uniform_int_distribution<int>::param_type(a,b) )
>>
>> Yes, this is correct according to the latest Working Draft for C++0X.
>>
>> >
>> > However, I think the intended way of using it is more like this:
>> >
>> > typedef uniform_int_distribution<int>::param_type range;
>> >
>> > uniform_int_distribution<int> u_int_d;
>> >
>> > c) u_int_d( gen, range(a,b) ); // reuse the same object!
>>
>> Yes, this is the intended way to use this two-argument function call
>> operator. However, we believe that the single-argument function call
>> operator will be used far more often in most programs.
>
> I have to admit that right now I'm thoroughly confused about param_type,
> and actually poring through all of its occurrences in the draft C++0X
> spec does not help. I applied the following procedure:
>
> 1. Search N2461 for "param_type"
>
> 2. Read the vicinity of every occurrence.
>
> No avail whatsoever. (I am assuming that N2461 is self-contained;
> otherwise, my point is moot.) Then I repeated the same procedure for
> "param(", thinking that the homonym function is explained somewhere. I
> did find an explanation in table 107 on page 855:
>
> Expression: u(e)
> Type: T
> Pre-post condition:
> With p = u.param(), the sequence amortized
> of numbers returned by successive constant number
> invocations with the same object e of invocations of
> is randomly distributed according e
> to the associated p(z | {p}) or
> P(zi | {p}) function.
>
> That's awfully little to go by in deducing what param_type and the
> param() functions are about.
Keeping in mind that "P is the type named by [the random number
distribution's] associated param_type," please take another look at
26.4.1.5 [rand.req.dist], especially paragraphs 6, 7, 8, and 9. Also
keep in mind as you look through Table 107 that "p is a value of P."
(Quotes from paragraph 1 of the same section.)
> I vaguely realise from having read past
> documents that the parameter parameterizes the distribution, e.g. for a
> Gaussian distribution the parameters would be \Sigma and \mu. Is that
> correct? If so, then it's unclear to me where it says that an integral
> distribution has one parameter that's its range. I looked all over
> uniform_int_distribution, it just doesn't say a thing.
Yes, each distribution can be constructed from an instance of its
corresponding param_type, which encapsulates all the necessary
parameters of that distribution. However, each distribution can also be
directly constructed from those parameters. For the uniform_int- and
uniform_real_distribution these parameters correspond to the range, but
this is not the general case for other distributions. As you point out,
normal_distribution has a constructor that takes a mean and a stddev; it
also has a constructor that takes a normal_distribution::param_type
that, in turn, is constructed with such a mean and stddev.
>
> A second issue I discovered while thinking of the random numbers library
> is that there's no generator called "random". There are various
> generators whose names tell _how_ the job is done, yet none that says
> _what_ job is being done and offers to readily take up the task.
>
> This might seem silly, but I think it's not. Think of Joe Coder trying
> to generate some random numbers. Joe happily pulls his just-installed
> C++0X's documentation, looks up random numbers, and sure enough, there's
> plenty of stuff to play with. The problem is that Joe does not know or
> care much about how random numbers are generated, so names like
> "linear_congruential_engine", "mersenne_twister_engine", or
> "hole_in_the_ground" are all just the same to him; he just wants to get
> work done. So Joe finds himself with an embarrassment of riches:
>
> 1. Should he use minstd_rand0?
>
> 2. minstd_rand perhaps? (That "0" didn't look that good anyway.)
>
> 3. The ungainly-named mt19937?
>
> 4. The Latin-sounding, luminous and optimistic ranlux* variety? (Fiat
Lux!)
>
> ..
>
> 10. Templatize the whole thing with the generator type and toss the
> choice point elsewhere?
>
> That's lots of choice, which is good if Joe's focus was Monte Carlo
> simulation, hashing, cryptography, and the such, but really, all Joe is
> trying here is to generate some plain vanilla random numbers.
>
> So I suggest the standard library provides a typedef called "random" (or
> "random_generator" etc.) for whatever the library implementation
> believes is the most appropriate generator for the given platform. On
> most platforms, probably:
>
> typedef mt19937 random;
>
> would do, and on a tight embedded system:
>
> typedef minstd_rand random;
>
> would be more appropriate.
>
> Don't get me wrong in criticizing the library; by and large, I think
> it's the best random number library design of all, by a mile. If I were
> a random number, I'd think I died and went to heaven. Yet, I find it a
> bit of a letdown that the new random library has all this great breadth
> and depth, but in my humble opinion it hasn't really dotted the last
> "i"s. Any complex library should be taken back to the simplest tasks
> it's supposed to fulfill and checked if it makes them easy enough.
Thank you for the kind words regarding this design.
Alas, it is well known that Standards documents are rarely, if ever,
useful as tutorials. The problem with trying to decide what might be
best for Joe Coder is that there's no way to decide. Sometimes he wants
speed of performance, sometimes he wants to minimize size, sometimes he
wants the best quality of randomness (which itself can be measured in
several different ways). No one engine is uniformly best on all counts,
but each of the predefined engines (the typedefs in 26.4.5
[rand.predef]) in the Standard has been recognized as "best" according
to some of these criteria.
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Mon, 29 Oct 2007 18:00:32 GMT Raw View
Hello,
I've studied Jens Maurer's TR1 random numbers
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html).
Very nicely done! I have a question-comment.
Quite often, what I need is to generate random integers in a given
range, e.g. (in a hypothetical Random framework):
Random rnd;
char digit = rnd.next<char>('0', '9');
unsigned length = rnd.next<unsigned>(1, 1023);
.
The code generating uniformly-distributed integers in a range is not
trivial, so a good random library should provide it in an encapsulated
form. Indeed, TR1 does exactly that: uniform_int<IntType> creates a
uniform distribution over a given range, using a uniform integer
generator as a back-end. So one can write:
minstd_rand gen;
uniform_int<char> dist1('0', '9');
uniform_int<unsigned> dist2(1, 1023);
char digit = dist1(gen);
unsigned length = dist2(gen);
The problem with this is that it's way verbose and requires one object
per range. Probably to assuage this issue, uniform_int offers another
function, of which use goes like this:
minstd_rand gen;
uniform_int<unsigned> dist(0, 0); // parameters do NOT matter
char digit = static_cast<char>('0' + dist(gen, '9' + 1));
unsigned length = 1 + dist(gen, 1023);
This turns a variety of red blinking LEDs on. An object initialized on a
premise is used for things not falling within that premise, to the
extent that the actual initialization of the object does not matter.
Also, there are casts all over the code like a cheap suit.
The quoted document has to say about this the following:
======================
result_type operator()(UniformRandomNumberGenerator& urng,
result_type n)
Returns: A uniform random number x in the range 0 <= x < n. [Note: This
allows a variate_generator object with a uniform_int distribution to be
used with std::random_shuffe (sic), see [lib.alg.random.shuffle]. ]
======================
My reading of the note is: "[We acknowledge this limitation of the
design, and this function compensates for it to some extent.]" This
little impurity propagates up to the variate_generator class.
So I'm asking whether there's an easy and simple way to generate
integral numbers within the TR1 framework. Did I overlook something? If
not, it would be great if a convenience type or function was present in
C++0X.
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 29 Oct 2007 21:21:32 GMT Raw View
Andrei Alexandrescu (See Website For Email) ha scritto:
>
> minstd_rand gen;
> uniform_int<char> dist1('0', '9');
> uniform_int<unsigned> dist2(1, 1023);
> char digit = dist1(gen);
> unsigned length = dist2(gen);
>
> The problem with this is that it's way verbose and requires one object
> per range.
You can write the same code like this:
minstd_rand gen;
char digit = uniform_int<char>('0', '9')(gen);
unsigned length = uniform_int<unsigned>(1, 1023)(gen);
The presence of the generator is a Good Thing(tm), otherwise you would
need some static generator instance and you would completely lose the
gift of re-entrancy. So if the generator stays, I can't think of any
construct significantly less verbose than that. The creation of the
temporary object should not bother you so much. I have seen at least one
optimizing compiler doing a wonderful job on this code snippet.
> So I'm asking whether there's an easy and simple way to generate
> integral numbers within the TR1 framework. Did I overlook something? If
> not, it would be great if a convenience type or function was present in
> C++0X.
You might think about something like
template <class Type, class Rng>
Type generate_uniform_int(Type a, Type b, Rng& gen)
{
return uniform_int<Type>(a, b)(gen);
}
but I see little value over the example I have shown above: all you gain
is the possible automatic deduction of Type. I frankly prefer specifying
Type explicitly as I usually do, for example, even with std::min/max.
HTH,
Ganesh
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@erdani.org>
Date: Mon, 29 Oct 2007 22:17:38 CST Raw View
Alberto Ganesh Barbati wrote:
> Andrei Alexandrescu (See Website For Email) ha scritto:
>> minstd_rand gen;
>> uniform_int<char> dist1('0', '9');
>> uniform_int<unsigned> dist2(1, 1023);
>> char digit = dist1(gen);
>> unsigned length = dist2(gen);
>>
>> The problem with this is that it's way verbose and requires one object
>> per range.
>
> You can write the same code like this:
>
> minstd_rand gen;
> char digit = uniform_int<char>('0', '9')(gen);
> unsigned length = uniform_int<unsigned>(1, 1023)(gen);
>
> The presence of the generator is a Good Thing(tm), otherwise you would
> need some static generator instance and you would completely lose the
> gift of re-entrancy. So if the generator stays, I can't think of any
> construct significantly less verbose than that. The creation of the
> temporary object should not bother you so much. I have seen at least one
> optimizing compiler doing a wonderful job on this code snippet.
Clearly the generator has to be in the picture.
But let's say the creation of the temporary object is not bothersome. In
that case, definitely the existence of the odd function
operator()(Generator&, SomeInt) _is_ bothersome! I mean, how come your
nice argument does not apply to using uniform_int for random_shuffle?
Either way you look at it, there is some redundancy.
>> So I'm asking whether there's an easy and simple way to generate
>> integral numbers within the TR1 framework. Did I overlook something? If
>> not, it would be great if a convenience type or function was present in
>> C++0X.
>
> You might think about something like
>
> template <class Type, class Rng>
> Type generate_uniform_int(Type a, Type b, Rng& gen)
> {
> return uniform_int<Type>(a, b)(gen);
> }
>
> but I see little value over the example I have shown above: all you gain
> is the possible automatic deduction of Type. I frankly prefer specifying
> Type explicitly as I usually do, for example, even with std::min/max.
Well I'd like it too, if there was a compelling argument in its favor. I
don't see one. So far, using the standard library does not necessitate
explicit type specification, and I don't see a need for the random
number generator to start a new trend.
Truth be told, with "auto" things will get a tad more palatable:
auto digit = uniform_int<char>('0', '9')(gen);
At least I can enjoy some weird Puritan satisfaction that I only
specified that I traffic in "char" three times instead of four.
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 30 Oct 2007 23:04:04 GMT Raw View
Andrei Alexandrescu (See Website For Email) ha scritto:
> Alberto Ganesh Barbati wrote:
>> Andrei Alexandrescu (See Website For Email) ha scritto:
>>> minstd_rand gen;
>>> uniform_int<char> dist1('0', '9');
>>> uniform_int<unsigned> dist2(1, 1023);
>>> char digit = dist1(gen);
>>> unsigned length = dist2(gen);
>>>
>>> The problem with this is that it's way verbose and requires one object
>>> per range.
>>
>> You can write the same code like this:
>>
>> minstd_rand gen;
>> char digit = uniform_int<char>('0', '9')(gen);
>> unsigned length = uniform_int<unsigned>(1, 1023)(gen);
>>
>> The presence of the generator is a Good Thing(tm), otherwise you would
>> need some static generator instance and you would completely lose the
>> gift of re-entrancy. So if the generator stays, I can't think of any
>> construct significantly less verbose than that. The creation of the
>> temporary object should not bother you so much. I have seen at least one
>> optimizing compiler doing a wonderful job on this code snippet.
>
> Clearly the generator has to be in the picture.
>
> But let's say the creation of the temporary object is not bothersome. In
> that case, definitely the existence of the odd function
> operator()(Generator&, SomeInt) _is_ bothersome! I mean, how come your
> nice argument does not apply to using uniform_int for random_shuffle?
> Either way you look at it, there is some redundancy.
I don't get your point. What does operator()(Generator&, SomeInt) matter
with the "The problem with this is that it's way verbose and requires
one object per range" issue?
By the way, I just had a look at the latest draft N2461 and things have
changed quite a bit from your references. For example the
variate_generator template does not exist anymore so the description of
operator()(g,p) no longer has a reference to it. On a side note,
uniform_int is now named uniform_int_distribution.
>>> So I'm asking whether there's an easy and simple way to generate
>>> integral numbers within the TR1 framework. Did I overlook something? If
>>> not, it would be great if a convenience type or function was present in
>>> C++0X.
>>
>> You might think about something like
>>
>> template <class Type, class Rng>
>> Type generate_uniform_int(Type a, Type b, Rng& gen)
>> {
>> return uniform_int<Type>(a, b)(gen);
>> }
>>
>> but I see little value over the example I have shown above: all you gain
>> is the possible automatic deduction of Type. I frankly prefer specifying
>> Type explicitly as I usually do, for example, even with std::min/max.
>
> Well I'd like it too, if there was a compelling argument in its favor.
> don't see one. So far, using the standard library does not necessitate
> explicit type specification, and I don't see a need for the random
> number generator to start a new trend.
I apologize, English is not my mother language. I don't understand what
is "it" in the sentence "I'd like it too" (I did not say that I like
generate_uniform_int, in fact I don't). The rest of the sentence is also
quite obscure to me. Could you please rephrase?
> Truth be told, with "auto" things will get a tad more palatable:
>
> auto digit = uniform_int<char>('0', '9')(gen);
>
> At least I can enjoy some weird Puritan satisfaction that I only
> specified that I traffic in "char" three times instead of four.
If you say so... I usually prefer having the type of variable clearly
shown, especially when I know it and the name is short as in this case.
Cheers,
Ganesh
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: wb@fnal.gov (Walter E Brown)
Date: Wed, 31 Oct 2007 14:59:15 GMT Raw View
On 2007-10-29 1:00 PM, Andrei Alexandrescu (See Website For Email) wrote:
> Hello,
>
> I've studied Jens Maurer's TR1 random numbers
> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html).
> Very nicely done! I have a question-comment.
Thank you. My colleagues at Fermilab and I collaborated with Jens at
the time he was preparing this proposal. As another poster in this
thread has pointed out, this portion of the standard library has
undergone substantial evolution and refinement since the early TR1
version to which you refer above.
Because your "question-comment" concerns itself with certain details of
what we consider a superseded version, I have snipped it from this posting.
I would respectfully recommend that, at your convenience, you look at
section [rand] (26.4) of committee paper N2461, the latest Working Draft
for C++0X, published just this week. You might also want to review the
latest description of the random-shuffle algorithm in section
[alg.random.shuffle] (25.2.12).
For some rationale and background regarding the changes since the TR1
version, you may want to have a look at some subset of the following
papers, listed in (roughly) reverse chronological order; as best I can
tell, this is the complete set of papers (over the five-year time span
2002 to date) related to this part of C++0X:
N2424 "Recommendations for Resolving the 2007-09-21 Issues re [rand]"
N2423 "Recommendations for Resolving Issues re [rand], version 2"
N2391 "Recommendations for Resolving Issues re [rand]"
N2111 "Random Number Generation in C++0X: A Comprehensive Proposal,
version 4"
N2079 "Random Number Generation in C++0X: A Comprehensive Proposal,
version 3"
N2032 "Random Number Generation in C++0X: A Comprehensive Proposal,
version 2"
N1932 "Random Number Generation in C++0X: A Comprehensive Proposal"
N2033 "Proposal to Consolidate the Subtract-with-Carry Engines"
N1933 "Improvements to TR1's Facility for Random Number Generation"
N1914 "A Proposal to Add Random-Number Distributions to C++0X
N1588 "On Random-Number Distributions for C++0X"
N1452 "A Proposal to Add an Extensible Random Number Facility to the
Standard Library (Revision 2)"
N1398 "A Proposal to Add an Extensible Random Number Facility to the
Standard Library"
After you've had a chance to bring yourself up to date, we would be
pleased to have your further comments.
Best,
-- WEB
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@erdani.org>
Date: Wed, 31 Oct 2007 10:47:31 CST Raw View
Alberto Ganesh Barbati wrote:
> I don't get your point. What does operator()(Generator&, SomeInt) matter
> with the "The problem with this is that it's way verbose and requires
> one object per range" issue?
It's very simple, really. The task is to generate an integral number in
the range [a, b]. I was saying there are two options:
a) Call uniform_int<int>(a, b)(gen)
b) Call a + uniform_int<int>(whatever, whatever)(gen, b + 1)
You say that (a) is a good option, efficiency-wise and all. Then I don't
understand why option (b) is in the picture. Why would people consume
interface real estate with a function that's not needed? The function
propagates up to variate_generator, so it's not an accident or an
oversight; there must be a reason.
> By the way, I just had a look at the latest draft N2461 and things have
> changed quite a bit from your references. For example the
> variate_generator template does not exist anymore so the description of
> operator()(g,p) no longer has a reference to it. On a side note,
> uniform_int is now named uniform_int_distribution.
I'm perusing:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
which does feature variate_generator and uniform_int. Then I searched
specifically for uniform_int_distribution and found:
www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2032.pdf
which indeed lacks the variate_generator and renames uniform_int to
uniform_int_distribution. I see with chagrin that the
operator()(UniformRandomNumberGenerator& urng, const param_type& parm)
is still there. I don't understand why. The nice thing is that the
function is constrained to a specific integral type param_type.
>>>> So I'm asking whether there's an easy and simple way to generate
>>>> integral numbers within the TR1 framework. Did I overlook something? If
>>>> not, it would be great if a convenience type or function was present in
>>>> C++0X.
>>> You might think about something like
>>>
>>> template <class Type, class Rng>
>>> Type generate_uniform_int(Type a, Type b, Rng& gen)
>>> {
>>> return uniform_int<Type>(a, b)(gen);
>>> }
>>>
>>> but I see little value over the example I have shown above: all you gain
>>> is the possible automatic deduction of Type. I frankly prefer specifying
>>> Type explicitly as I usually do, for example, even with std::min/max.
>> Well I'd like it too, if there was a compelling argument in its favor.
>> don't see one. So far, using the standard library does not necessitate
>> explicit type specification, and I don't see a need for the random
>> number generator to start a new trend.
>
> I apologize, English is not my mother language. I don't understand what
> is "it" in the sentence "I'd like it too" (I did not say that I like
> generate_uniform_int, in fact I don't). The rest of the sentence is also
> quite obscure to me. Could you please rephrase?
I meant: "I'd like to specify the type too, if there was a compelling
argument in favor of doing so".
>> Truth be told, with "auto" things will get a tad more palatable:
>>
>> auto digit = uniform_int<char>('0', '9')(gen);
>>
>> At least I can enjoy some weird Puritan satisfaction that I only
>> specified that I traffic in "char" three times instead of four.
>
> If you say so... I usually prefer having the type of variable clearly
> shown, especially when I know it and the name is short as in this case.
Experience with "auto" tends to suggest that omitting redundant type
names generally makes for more robust code. Lacking hard evidence, I
guess there's not much of a point I can make though :o).
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Wed, 31 Oct 2007 22:19:25 GMT Raw View
Walter E Brown wrote:
> On 2007-10-29 1:00 PM, Andrei Alexandrescu (See Website For Email)
> wrote:
>> Hello,
>>
>> I've studied Jens Maurer's TR1 random numbers
>> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html).
>> Very nicely done! I have a question-comment.
>
> Thank you. My colleagues at Fermilab and I collaborated with Jens at
> the time he was preparing this proposal. As another poster in this
> thread has pointed out, this portion of the standard library has
> undergone substantial evolution and refinement since the early TR1
> version to which you refer above.
>
> Because your "question-comment" concerns itself with certain details
> of what we consider a superseded version, I have snipped it from this
> posting.
>
> I would respectfully recommend that, at your convenience, you look at
> section [rand] (26.4) of committee paper N2461, the latest Working
> Draft for C++0X, published just this week. You might also want to
> review the latest description of the random-shuffle algorithm in
> section [alg.random.shuffle] (25.2.12).
Thanks for the flowery language :o). An URL would have been equally
appreciated. Are you, for example, referring to the N2461 available from
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007 ?
[snip]
> After you've had a chance to bring yourself up to date, we would be
> pleased to have your further comments.
While I'm thoroughly impressed by you walking me through the mentioned
bibliography, if what I wanted was to absorb all of the minutiae of the
random numbers, probably I wouldn't even have written here. What I was
hoping was a simple answer to a simple question from someone who already
knows that information. Sure if someone asked me a simple question about
machine learning I wouldn't send her to read everything from Vapnik's
1974 paper onward.
Andrei
---
[ 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.comeaucomputing.com/csc/faq.html ]