Re: Range of random numbers
"bearophile" , dans le message (digitalmars.D.learn:35148), a écrit : > Why don't you write a little benchmark to compare the performance > of the two versions? Because I'm interested in the code's meaning for the human reader, not the performance. I actually think : "map!(_=> uniform(a, b))(repeat(0))" is better, because it puts the call to uniform first, and the _ indicates that the rest is unimportant. For you curiosity, this is the benchmark using: gdc (GCC) 4.7.0 20120322 (gdc 0.31 - r805:0414cec152c7, using dmd 2.057) and gdc -O3 testRNG.d && ./a.out import std.array, std.range, std.algorithm, std.random, std.stdio, std.datetime; auto uniformRange1(T1, T2, T3)(T1 a, T2 b, T3 gen) { return map!((x) {return x();} ) (repeat((){return uniform(a, b, gen);})); } auto uniformRange2(T1, T2, T3)(T1 a, T2 b, T3 gen) { return map!((x) { return uniform(a, b, gen); })(repeat(0)); } auto uniformRange3(T1, T2, T3)(T1 a, T2 b, T3 gen) { return map!((x) { return uniform(a, b, gen); })(cycle([0])); } void f1() { auto ur = array(take(uniformRange1(0, 10, Xorshift(1)), 1000)); } void f2() { auto ur = array(take(uniformRange2(0, 10, Xorshift(1)), 1000)); } void f3() { auto ur = array(take(uniformRange3(0, 10, Xorshift(1)), 1000)); } void main() { auto b=benchmark!(f1, f2, f3)(1000); writeln(b[0].to!("seconds",double),"s, ", b[1].to!("seconds",double), "s, ", b[2].to!("seconds",double),"s." ); // outputs : // 0.040437s, 0.0393537s, 0.0486439s } f2 performs 23% better than f3, and 3% better than f1. -- Christophe
Re: Range of random numbers
On 24/04/12 13:50, Christophe wrote: We could also use a template to make a range out of a delegate and avoid this workarround... What I'd _really_ like to see is something which would allow you to generate a range of random numbers with an expression like, auto rr = randomRange!distribution(/* distribution parameters */); or, auto rr = randomRange!distribution(size_t n, /* distribution parameters */); ... which would generate you either an infinite or length-n range of random numbers generated by the specified distribution, with the passed parameters. So, you could call e.g., auto rr = randomRange!(uniform!"()")(100, 0.0, 1.0); auto rr = randomRange!pareto(100, alpha, sigma); auto rr = randomRange!exponential(lambda); ... etc. But I'm not sure if this is feasible.
Re: Range of random numbers
trav...@phare.normalesup.org: That looks like a workarround, not meaningful code. It wasn't terrible code :-) How about return repeat(_ =>uniform(lower, upper)).map!(x => x())(); ? Why don't you write a little benchmark to compare the performance of the two versions? Using uniform(lower, upper, gen) with auto gen = Xorshift(1); to reduce influence from the random generator. Bye, bearophile
Re: Range of random numbers
"bearophile" , dans le message (digitalmars.D.learn:35108), a écrit : > What about (untested): > > auto uniformRange(T1 lower, T2 upper) { > return count().map!(_ => uniform(lower, upper))(); > } That looks like a workarround, not meaningful code. How about return repeat(_ =>uniform(lower, upper)).map!(x => x())(); ? We could also use a template to make a range out of a delegate and avoid this workarround... struct RepeatDg(T) { T delegate() dg; this(T delegate() dg_) { dg = dg_; } @property enum bool empty = false; @property T front() { return dg(); } @property void popFront() {} }
Re: Range of random numbers
Count(5) is easy to replace with iota(5, int.max), This also means that for the OP problem, using repeat(0) is more correct than using count(), because count on default yields ints, that are limited to about 2 milliards. Bye, bearophile
Re: Range of random numbers
jerro: Couldn't it just be iota with no parameters? The Count range has a helper count() function similar to this, that's meant to have an argument that defaults to zero: Count!T count(T)(T start=0) if (isIntegral!T) { return Count!T(start); } The argument allows it to start from another starting point, and it allows you to specify the type of the numbers it yields, while in iota() without arguments it's less easy to specify the type of the numbers it yields. Count(5) is easy to replace with iota(5, int.max), but count(BigInt(0)) is less easy to replace with iota, because it doesn't give you a way to denote a right-open BigInt interval. And using iota(BigInt(0), BigInt(ulong.max)) is not that good. Currently using BigInt in iota seems to not even being supported... Bye, bearophile
Re: Range of random numbers
It's for a different purpose. So the count() I was proposing will need a different name. Couldn't it just be iota with no parameters?
Re: Range of random numbers
On 04/23/2012 10:56 AM, Joseph Rushton Wakeling wrote: On 23/04/12 19:46, Joseph Rushton Wakeling wrote: On 23/04/12 18:56, bearophile wrote: jerro: return repeat(0).map!(_ => uniform(lower, upper))(); Yes, this works nicely. Thanks very much! Is this a new addition? With GDC I get a compiler error: expression expected, not '>' ... suggesting => isn't supported. The lambda syntax was added in 2.058: http://dlang.org/changelog.html Ali
Re: Range of random numbers
On 23/04/12 19:46, Joseph Rushton Wakeling wrote: On 23/04/12 18:56, bearophile wrote: jerro: return repeat(0).map!(_ => uniform(lower, upper))(); Yes, this works nicely. Thanks very much! Is this a new addition? With GDC I get a compiler error: expression expected, not '>' ... suggesting => isn't supported.
Re: Range of random numbers
On 23/04/12 18:56, bearophile wrote: jerro: return repeat(0).map!(_ => uniform(lower, upper))(); repeat(0) returns the same sequence as cycle([0]) and is as fast as it gets, since popFront does nothing and empty is an enum. Good idea. Yes, this works nicely. Thanks very much!
Re: Range of random numbers
jerro: > return repeat(0).map!(_ => uniform(lower, upper))(); > > repeat(0) returns the same sequence as cycle([0]) and is as fast > as it gets, since popFront does nothing and empty is an enum. Good idea. --- Dmitry Olshansky: > What's wrong with: > http://dlang.org/phobos/std_algorithm.html#count It's for a different purpose. So the count() I was proposing will need a different name. Bye, bearophile
Re: Range of random numbers
What about (untested): auto uniformRange(T1 lower, T2 upper) { return count().map!(_ => uniform(lower, upper))(); } Where count() is just: http://d.puremagic.com/issues/show_bug.cgi?id=7839 In the meantime cycle([0]) is acceptable but slower (untested): return cycle([0]).map!(_ => uniform(lower, upper))(); He could also use repeat in this case: return repeat(0).map!(_ => uniform(lower, upper))(); repeat(0) returns the same sequence as cycle([0]) and is as fast as it gets, since popFront does nothing and empty is an enum.
Re: Range of random numbers
On 23.04.2012 17:52, bearophile wrote: Joseph Rushton Wakeling: struct UniformRange(T1, T2) { T1 _lower; T2 _upper; @property enum bool empty = false; this(T1 a, T2 b) { _lower = a; _upper = b; } @property auto ref front() { assert(!empty); return uniform(_lower, _upper); } void popFront() { } } What about (untested): auto uniformRange(T1 lower, T2 upper) { return count().map!(_ => uniform(lower, upper))(); } Where count() is just: http://d.puremagic.com/issues/show_bug.cgi?id=7839 What's wrong with: http://dlang.org/phobos/std_algorithm.html#count In the meantime cycle([0]) is acceptable but slower (untested): return cycle([0]).map!(_ => uniform(lower, upper))(); Bye, bearophile -- Dmitry Olshansky
Re: Range of random numbers
Joseph Rushton Wakeling: struct UniformRange(T1, T2) { T1 _lower; T2 _upper; @property enum bool empty = false; this(T1 a, T2 b) { _lower = a; _upper = b; } @property auto ref front() { assert(!empty); return uniform(_lower, _upper); } void popFront() { } } What about (untested): auto uniformRange(T1 lower, T2 upper) { return count().map!(_ => uniform(lower, upper))(); } Where count() is just: http://d.puremagic.com/issues/show_bug.cgi?id=7839 In the meantime cycle([0]) is acceptable but slower (untested): return cycle([0]).map!(_ => uniform(lower, upper))(); Bye, bearophile
Range of random numbers
For some reason this got lost in the ether, so I'm resending. Related to my earlier question on passing a function -- I was wondering if there's a trivial way of generating a lazily-evaluated range of random numbers according to a given distribution and parameters. I wrote up the code below to generate a range of uniformly-distributed numbers, but am not sure how to generalize it for arbitrary distribution and/or parameters, and I'm also not sure that I'm overcomplicating what might be more easily achieved with existing D functionality. The larger goal here is that I want some way to pass an _arbitrary_ number source (may be deterministic, may be stochastic) to a function. A range seemed a good way to do that (after all, in the deterministic case I can just pass an array, no?). ... but I couldn't work out how to generalize the stochastic case beyond what's shown here. /// import std.array, std.random, std.range, std.stdio; struct UniformRange(T1, T2) { T1 _lower; T2 _upper; @property enum bool empty = false; this(T1 a, T2 b) { _lower = a; _upper = b; } @property auto ref front() { assert(!empty); return uniform(_lower, _upper); } void popFront() { } } auto uniformRange(T1, T2)(T1 a, T2 b) { return UniformRange!(T1, T2)(a, b); } auto uniformRange(T1, T2)(size_t n, T1 a, T2 b) { return take(UniformRange!(T1, T2)(a, b), n); } void main() { auto ur = uniformRange!(double, double)(5, 10.0, 20.0); double[] x = array( take(uniformRange(1.0, 2.0), 5) ); double[] y = array(x); foreach(r; ur) writeln(r); writeln; foreach(r; ur) writeln(r); writeln; foreach(r; x) writeln(r); writeln; foreach(r; y) writeln(r); writeln; }