Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Ticket #1155: patchRandom.txt

File patchRandom.txt, 15.6 kB (added by fawzi, 5 months ago)

patch for random (apply with patch)

Line 
1 Index: tango/math/Random.d
2 ===================================================================
3 --- tango/math/Random.d (revision 3630)
4 +++ tango/math/Random.d (working copy)
5 @@ -11,8 +11,10 @@
6  *******************************************************************************/
7  
8  module tango.math.Random;
9 +import tango.io.protocol.model.IWriter:IWritable,IWriter;
10 +import tango.io.protocol.model.IReader:IReadable,IReader;
11 +import Integer = tango.text.convert.Integer;
12  
13 -
14  version (Win32)
15           private extern(Windows) int QueryPerformanceCounter (ulong *);
16  
17 @@ -21,6 +23,17 @@
18          private import tango.stdc.posix.sys.time;
19          }
20  
21 +/// compile time integer power
22 +private T powI(T)(T x,int p){
23 +    T xx=cast(T)1;
24 +    if (p<0){
25 +        p=-p;
26 +        x=1/x;
27 +    }
28 +    for (int i=0;i<p;++i)
29 +        xx*=x;
30 +    return xx;
31 +}
32  
33  /******************************************************************************
34  
35 @@ -41,9 +54,12 @@
36  
37          The period of KISS is thus 2^32*(2^32-1)*(2^63+2^32-1) > 2^127
38  
39 +        Conversion to floating point generalizing Dr Jurgen A Doornik
40 +        "Conversion of high-period random numbers to floating point"
41 +
42  ******************************************************************************/
43  
44 -class Random
45 +final class Random : IWritable, IReadable
46  {
47          /**********************************************************************
48  
49 @@ -94,7 +110,7 @@
50  
51          **********************************************************************/
52  
53 -        final Random seed ()
54 +        Random seed ()
55          {
56                  ulong s;
57  
58 @@ -117,7 +133,7 @@
59  
60          **********************************************************************/
61  
62 -        final Random seed (uint seed)
63 +        Random seed (uint seed)
64          {
65                  kiss_x = seed | 1;
66                  kiss_y = seed | 2;
67 @@ -133,7 +149,7 @@
68  
69          **********************************************************************/
70  
71 -        final uint next ()
72 +        uint next ()
73          {
74                  kiss_x = kiss_x * 69069 + 1;
75                  kiss_y ^= kiss_y << 13;
76 @@ -156,7 +172,7 @@
77  
78          **********************************************************************/
79  
80 -        final uint next (uint max)
81 +        uint next (uint max)
82          {
83                  return next() % max;
84          }
85 @@ -170,9 +186,334 @@
86  
87          **********************************************************************/
88  
89 -        final uint next (uint min, uint max)
90 +        uint next (uint min, uint max)
91          {
92                  return next(max-min) + min;
93          }
94 +
95 +        /**********************************************************************
96 +                Returns a value between 0 and 1, exclusive
97 +         maybe here a bit transfer would be better, as it is faster, but then
98 +         avoiding 0 is more difficult
99 +        **********************************************************************/
100 +        double nextFloat ()
101 +        {
102 +            static assert(float.mant_dig<=33,"float mantissa expected to be at most 33 (32 normalized) bit");
103 +            const float factS=powI(0.5f,float.mant_dig-1),shiftS=0.5f+0.5f*factS;
104 +            const uint maskS=(~0u)>>(33-float.mant_dig);
105 +            const int shift1=-(1<<(float.mant_dig-2));
106 +            uint nV=next;
107 +            int v1=cast(int)(nV & maskS)+shift1;
108 +            return (v1 * factS + shiftS);
109 +        }
110 +        /**********************************************************************
111 +                Returns a value between 0 and 1, exclusive
112 +        **********************************************************************/
113 +        double nextDouble ()
114 +        {
115 +            const double fact32=powI(0.5,32),factD=powI(0.5,double.mant_dig-1),
116 +                shiftD=0.5+0.5*factD;
117 +            const uint maskD=(~0u)>>(65-double.mant_dig);
118 +            static assert(32<double.mant_dig && double.mant_dig<=64,
119 +                "double mantissa expected to be between 32 and 64 bits");
120 +            return ((cast(int)next) * fact32 + shiftD +(next & maskD) * factD);
121 +        }
122 +       
123 +        /**********************************************************************
124 +                Returns a value between 0 and 1, exclusive
125 +        **********************************************************************/
126 +        real nextReal ()
127 +        {
128 +            static assert(33<real.mant_dig && real.mant_dig<=65,
129 +                "sizes larger than 65 bits or smaller than 33 (64 32 normalized) not suported");
130 +            const real fact32=powI(0.5L,32),factR=powI(0.5L,real.mant_dig-1),
131 +                shiftR=0.5L+0.5L*factR;
132 +            const uint maskR=(~0u)>>(65-real.mant_dig);
133 +            return ((cast(int)next) * fact32 + shiftR +(next & maskR) * factR);
134 +        }
135 +        /// randomizes the given array and returns it (for some types this is potentially
136 +        /// more efficient, both from the use of random numbers and speedwise)
137 +        byte[] randomize(byte[] a){
138 +            uint val=next; /// begin without value?
139 +            int rest=4;
140 +            for (size_t i=0;i<a.length;++i) {
141 +                if (rest!=0){
142 +                    a[i]=cast(byte)(0xFF&val);
143 +                    val>>=8;
144 +                    --rest;
145 +                } else {
146 +                    val=next;
147 +                    a[i]=cast(byte)(0xFF&val);
148 +                    val>>=8;
149 +                    rest=3;
150 +                }
151 +            }
152 +            return a;
153 +        }
154 +        ubyte[] randomize(ubyte[] a){
155 +            uint val=next; /// begin without value?
156 +            int rest=4;
157 +            for (size_t i=0;i<a.length;++i) {
158 +                if (rest!=0){
159 +                    a[i]=cast(ubyte)(0xFF&val);
160 +                    val>>=8;
161 +                    --rest;
162 +                } else {
163 +                    val=next;
164 +                    a[i]=cast(ubyte)(0xFF&val);
165 +                    val>>=8;
166 +                    rest=3;
167 +                }
168 +            }
169 +            return a;
170 +        }
171 +        uint[] randomize(uint[] a){
172 +            for (size_t i=0;i<a.length;++i)
173 +                a[i]=next;
174 +            return a;
175 +        }
176 +        /// ditto
177 +        int[] randomize(int[] a){
178 +            for (size_t i=0;i<a.length;++i)
179 +                a[i]=cast(int)next;
180 +            return a;
181 +        }
182 +        /// ditto
183 +        float[] randomize(float[] a){
184 +            static assert(float.mant_dig<=33,
185 +                "float mantissa expected to be at most 33 (32 normalized) bit");
186 +            const float factS=powI(0.5f,float.mant_dig-1),shiftS=0.5f+0.5f*factS;
187 +            const uint maskS=(~0u)>>(33-float.mant_dig),
188 +                maskRest=~maskS;
189 +            const int shift1=-(1<<(float.mant_dig-2));
190 +            const int nbitRest=33-float.mant_dig;
191 +            uint rest=0,nV;
192 +            int nrest=32-nbitRest;
193 +            foreach(ref el;a){
194 +                if (nrest<0){
195 +                    nrest=32-nbitRest;
196 +                    nV=rest;
197 +                } else {
198 +                    nV=next;
199 +                    rest|= maskRest & nV;
200 +                    rest>>=nbitRest;
201 +                    nrest-=nbitRest;
202 +                }
203 +                int v1=cast(int)(nV & maskS)+shift1;
204 +                el=(v1 * factS + shiftS);
205 +            }
206 +            return a;
207 +        }
208 +        /// ditto
209 +        double[] randomize(double[] a){
210 +            const double fact32=powI(0.5,32),factD=powI(0.5L,double.mant_dig-1),
211 +                shiftD=0.5L+0.5L*factD;
212 +            const uint maskD=(~0u)>>(65-double.mant_dig),
213 +                maskRest= ~maskD;
214 +            const int nbitRest=65-double.mant_dig;
215 +            uint rest=0,nV;
216 +            int nrest=32-nbitRest;
217 +            foreach (ref el;a){
218 +                if (nrest<0){
219 +                    nrest=32-nbitRest;
220 +                    nV=rest;
221 +                } else {
222 +                    nV=next;
223 +                    rest|= maskRest & nV;
224 +                    rest>>=nbitRest;
225 +                    nrest-=nbitRest;
226 +                }
227 +                el=((cast(int)next) * fact32 +(nV & maskD) * factD + shiftD);
228 +            }
229 +            return a;
230 +        }
231 +        /// ditto
232 +        real[] randomize(real[] a){
233 +            const real fact32=powI(0.5L,32),factR=powI(0.5L,real.mant_dig-1),
234 +                shiftR=0.5L+0.5L*factR;
235 +            const uint maskR=(~0u)>>(65-real.mant_dig),
236 +                maskRest= ~maskR;
237 +            static if (real.mant_dig>=63){
238 +                /// avoid all the overhead for just few bits...
239 +                foreach (ref el;a){
240 +                    el=((cast(int)next) * fact32 + shiftR +(maskR & next) * factR);
241 +                }
242 +            } else {
243 +                const int nbitRest=65-real.mant_dig;
244 +                uint rest=0,nV;
245 +                int nrest=32-nbitRest;
246 +                foreach (ref el;a){
247 +                    if (nrest<0){
248 +                        nrest=32-nbitRest;
249 +                        nV=rest;
250 +                    } else {
251 +                        nV=next;
252 +                        rest<<=nbitRest;
253 +                        rest|= maskRest & nV;
254 +                        nrest-=nbitRest;
255 +                    }
256 +                    el=((cast(int)next) * fact32 +(nV & maskR) * factR + shiftR);
257 +                }
258 +            }
259 +            return a;
260 +        }
261 +       
262 +        ///  IWritable implementation
263 +        void write (IWriter input){
264 +            input(kiss_k)(kiss_m)(kiss_x)(kiss_y)(kiss_z)(kiss_w)(kiss_carry);
265 +        }
266 +        /// IReadable implementation
267 +        void read (IReader input){
268 +            input(kiss_k)(kiss_m)(kiss_x)(kiss_y)(kiss_z)(kiss_w)(kiss_carry);
269 +        }
270 +        /// writes the current status in a string
271 +        char[] toString(){
272 +            char[] res=new char[12+7*8];
273 +            int i=0;
274 +            res[i..5]="KISS1";
275 +            i+=5;
276 +            foreach (val;[kiss_k,kiss_m,kiss_x,kiss_y,kiss_z,kiss_w,kiss_carry]){
277 +                res[i]='_';
278 +                ++i;
279 +                Integer.format(res[i..i+8],val,"x8");
280 +                i+=8;
281 +            }
282 +            assert(i==res.length,"unexpected size");
283 +            return res;
284 +        }
285 +        /// reads the current status from a string (that should have been trimmed)
286 +        /// returns the number of chars read
287 +        uint fromString(char[] s){
288 +            uint i=0;
289 +            assert(s[i..i+4]=="KISS","unexpected kind, expected KISS");
290 +            assert(s[i+4..i+6]=="1_","unexpected version, expected 1");
291 +            i+=5;
292 +            foreach (val;[&kiss_k,&kiss_m,&kiss_x,&kiss_y,&kiss_z,&kiss_w,&kiss_carry]){
293 +                assert(s[i]=='_',"no separator _ found");
294 +                ++i;
295 +                uint ate;
296 +                *val=cast(uint)Integer.convert(s[i..i+8],16,&ate);
297 +                assert(ate==8,"unexpected read size");
298 +                i+=8;
299 +            }
300 +            return i;
301 +        }
302  }
303  
304 +debug(UnitTest){
305 +    import tango.stdc.stdio:printf;
306 +    import tango.io.protocol.Writer;
307 +    import tango.io.protocol.Reader;
308 +    import tango.io.Buffer;
309 +
310 +    void printStat(T)(T[] a, bool checkB=false){
311 +        T minV,maxV;
312 +        real meanV=0.0L;
313 +        if (a.length>0){
314 +            minV=a[0];
315 +            maxV=a[0];
316 +            foreach (el;a){
317 +                assert(!checkB || (cast(T)0<el && el<cast(T)1),"el out of bounds");
318 +                if (el<minV) minV=el;
319 +                if (el>maxV) maxV=el;
320 +                meanV+=cast(real)el;
321 +            }
322 +            meanV/=cast(real)a.length;
323 +            bool printM=false;
324 +            if (checkB) {
325 +                if (minV>0.2) printM=true;
326 +                if (maxV<0.8) printM=true;
327 +                if (0.3>meanV || meanV>0.7) printM=true;
328 +            } else {
329 +                real offset=0.2L*(cast(real)T.max-cast(real)T.min);
330 +                real rMean=0.5L*(cast(real)T.max+cast(real)T.min);
331 +                if (cast(real)minV>cast(real)T.min+offset) printM=true;
332 +                if (cast(real)maxV<cast(real)T.max-offset) printM=true;
333 +                if (rMean-offset>meanV || meanV>rMean+offset) printM=true;
334 +            }
335 +            if (printM)
336 +                printf("WARNING tango.math.Random statistic is strange: %.*s[%d] %Le %Le %Le\n\0",cast(int)T.stringof.length,T.stringof.ptr,a.length,cast(real)minV,meanV,cast(real)maxV);
337 +        }
338 +    }
339 +
340 +    unittest {
341 +        // test float corner cases
342 +        uint zeros=0u,ones=~0u,nneg=0x8000_0000,ppos=0x7FFF_FFFF;
343 +        const float factS=powI(0.5f,float.mant_dig-1),shiftS=0.5f+0.5f*factS;
344 +        const uint maskS=(~0u)>>(33-float.mant_dig);
345 +        const int shift1=-1<<(float.mant_dig-2);
346 +        int v1=cast(int)(zeros & maskS)+shift1;
347 +        float f1=(v1 * factS + shiftS);
348 +        assert(f1>0.0f && f1<1.0f,"float conversion out of bounds");
349 +        v1=cast(int)(ones & maskS)+shift1;
350 +        float f2=(v1 * factS + shiftS);
351 +        assert(f2>0.0f && f2<1.0f,"float conversion out of bounds");
352 +        assert(1.0f-f2==f1,"float conversion of 0 and 0xFFFFFFFF, no symmetry");
353 +        assert(float.epsilon>f1,"minimum float bigger or equal epsilon");
354 +        // test double corner cases
355 +        const double fact32=powI(0.5,32),factD=powI(0.5,double.mant_dig-1),
356 +        shiftD=0.5+0.5*factD;
357 +        const uint maskD=(~0u)>>(65-double.mant_dig);
358 +        double d1=((cast(int)nneg) * fact32 + shiftD +(zeros & maskD) * factD);
359 +        double d2=((cast(int)ppos) * fact32 + shiftD +(ones & maskD) * factD);
360 +        assert(d1>0.0 && d2<1.0,"double conversion out of bounds");
361 +        assert(d2>0.0 && d2<1.0,"double conversion out of bounds");
362 +        assert(1.0-d2==d1,"double conversion of 0 and 0xFFFFFFFF, no symmetry");
363 +        assert(double.epsilon>d1,"minimum double bigger or equal epsilon");
364 +        // test real corner cases
365 +        const real fact32R=powI(0.5L,32),factR=powI(0.5L,real.mant_dig-1),
366 +            shiftR=0.5L+0.5L*factR;
367 +        const uint maskR=(~0u)>>(65-real.mant_dig);
368 +        real r1=((cast(int)nneg) * fact32R + shiftR +(zeros & maskR) * factR);
369 +        real r2=((cast(int)ppos) * fact32R + shiftR +(ones & maskR) * factR);
370 +        assert(r1>0.0L && r2<1.0L,"real conversion out of bounds");
371 +        assert(r2>0.0L && r2<1.0L,"real conversion out of bounds");
372 +        assert(1.0L-r2==r1,"real conversion of 0 and 0xFFFFFFFF, no symmetry");
373 +        assert(real.epsilon>r1,"minimum real bigger or equal epsilon");
374 +        Random r=new Random();
375 +       
376 +        // checkpoint status (str or writer)
377 +        char[] status=r.toString();
378 +        Buffer buf=new Buffer(100);
379 +        auto reader = new Reader (buf);
380 +        auto writer = new Writer (buf);
381 +        writer(r);
382 +       
383 +        uint tVal=r.next;
384 +        int count=10_000;
385 +        for (int i=count;i!=0;--i){
386 +            float f=r.nextFloat();
387 +            assert(0<f && f<1,"float out of bounds");
388 +            double d=r.nextDouble();
389 +            assert(0<d && d<1,"double out of bounds");
390 +            real rr=r.nextReal();
391 +            assert(0<rr && rr<1,"double out of bounds");
392 +        }
393 +        byte[1000] barr;
394 +        ubyte[1000] ubarr;
395 +        uint[1000] uiarr;
396 +        int[1000] iarr;
397 +        float[1000] farr;
398 +        double[1000] darr;
399 +        real[1000] rarr;
400 +        r.randomize(barr);
401 +        printStat(barr);
402 +        r.randomize(ubarr);
403 +        printStat(ubarr);
404 +        r.randomize(uiarr);
405 +        printStat(uiarr);
406 +        r.randomize(iarr);
407 +        printStat(iarr);
408 +        r.randomize(farr);
409 +        printStat(farr,true);
410 +        r.randomize(darr);
411 +        printStat(darr,true);
412 +        r.randomize(rarr);
413 +        printStat(rarr,true);
414 +        r.fromString(status);
415 +        assert(r.next==tVal,"restoring of status from str failed");
416 +        reader(r);
417 +        assert(r.next==tVal,"restoring of status from writer failed");
418 +    }
419 +
420 +}