numru-narray 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,444 @@
1
+ /*
2
+ na_random.c
3
+ Numerical Array Extention for Ruby
4
+ (C) Copyright 2003-2008 by Masahiro TANAKA
5
+
6
+ This program is free software.
7
+ You can distribute/modify this program
8
+ under the same terms as Ruby itself.
9
+ NO WARRANTY.
10
+ */
11
+
12
+ /*
13
+ This is based on trimmed version of MT19937. To get the original version,
14
+ contact <http://www.math.keio.ac.jp/~matumoto/emt.html>.
15
+
16
+ The original copyright notice follows.
17
+
18
+ A C-program for MT19937, with initialization improved 2002/2/10.
19
+ Coded by Takuji Nishimura and Makoto Matsumoto.
20
+ This is a faster version by taking Shawn Cokus's optimization,
21
+ Matthe Bellew's simplification, Isaku Wada's real version.
22
+
23
+ Before using, initialize the state by using init_genrand(seed)
24
+ or init_by_array(init_key, key_length).
25
+
26
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
27
+ All rights reserved.
28
+
29
+ Redistribution and use in source and binary forms, with or without
30
+ modification, are permitted provided that the following conditions
31
+ are met:
32
+
33
+ 1. Redistributions of source code must retain the above copyright
34
+ notice, this list of conditions and the following disclaimer.
35
+
36
+ 2. Redistributions in binary form must reproduce the above copyright
37
+ notice, this list of conditions and the following disclaimer in the
38
+ documentation and/or other materials provided with the distribution.
39
+
40
+ 3. The names of its contributors may not be used to endorse or promote
41
+ products derived from this software without specific prior written
42
+ permission.
43
+
44
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
48
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
49
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
50
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
51
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
52
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
53
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55
+
56
+
57
+ Any feedback is very welcome.
58
+ http://www.math.keio.ac.jp/matumoto/emt.html
59
+ email: matumoto@math.keio.ac.jp
60
+ */
61
+ #include "ruby.h"
62
+ #include "narray.h"
63
+ #include "narray_local.h"
64
+
65
+ /* Period parameters */
66
+ #define N 624
67
+ #define M 397
68
+ #define MATRIX_A 0x9908b0dfUL /* constant vector a */
69
+ #define UMASK 0x80000000UL /* most significant w-r bits */
70
+ #define LMASK 0x7fffffffUL /* least significant r bits */
71
+ #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
72
+ #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
73
+
74
+ static u_int32_t state[N]; /* the array for the state vector */
75
+ static int left = 1;
76
+ static int initf = 0;
77
+ static u_int32_t *next;
78
+
79
+ /* initializes state[N] with a seed */
80
+ static void
81
+ init_genrand(u_int32_t s)
82
+ {
83
+ int j;
84
+ state[0]= s & 0xffffffffUL;
85
+ for (j=1; j<N; ++j) {
86
+ state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
87
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
88
+ /* In the previous versions, MSBs of the seed affect */
89
+ /* only MSBs of the array state[]. */
90
+ /* 2002/01/09 modified by Makoto Matsumoto */
91
+ state[j] &= 0xffffffffUL; /* for >32 bit machines */
92
+ }
93
+ left = 1; initf = 1;
94
+ }
95
+
96
+ static void
97
+ next_state()
98
+ {
99
+ u_int32_t *p=state;
100
+ int j;
101
+
102
+ /* if init_genrand() has not been called, */
103
+ /* a default initial seed is used */
104
+ if (initf==0) init_genrand(5489UL);
105
+
106
+ left = N;
107
+ next = state;
108
+
109
+ for (j=N-M+1; --j; ++p)
110
+ *p = p[M] ^ TWIST(p[0], p[1]);
111
+
112
+ for (j=M; --j; ++p)
113
+ *p = p[M-N] ^ TWIST(p[0], p[1]);
114
+
115
+ *p = p[M-N] ^ TWIST(p[0], state[0]);
116
+ }
117
+
118
+ #undef N
119
+ #undef M
120
+
121
+ /* These real versions are due to Isaku Wada, 2002/01/09 added */
122
+
123
+ #ifdef HAVE_UNISTD_H
124
+ #include <unistd.h>
125
+ #endif
126
+ #include <time.h>
127
+ #ifdef HAVE_SYS_TIME_H
128
+ #include <sys/time.h>
129
+ #endif
130
+
131
+ static int first = 1;
132
+
133
+ static int
134
+ rand_init(seed)
135
+ u_int32_t seed;
136
+ {
137
+ static u_int32_t saved_seed;
138
+ u_int32_t old;
139
+
140
+ first = 0;
141
+ init_genrand(seed);
142
+ old = saved_seed;
143
+ saved_seed = seed;
144
+
145
+ return old;
146
+ }
147
+
148
+ static u_int32_t
149
+ random_seed()
150
+ {
151
+ static int n = 0;
152
+ struct timeval tv;
153
+
154
+ gettimeofday(&tv, 0);
155
+ return tv.tv_sec ^ tv.tv_usec ^ getpid() ^ n++;
156
+ }
157
+
158
+ static VALUE
159
+ na_s_srand(int argc, VALUE *argv, VALUE obj)
160
+ {
161
+ VALUE sd;
162
+ u_int32_t seed, old;
163
+
164
+ rb_secure(4);
165
+ if (rb_scan_args(argc, argv, "01", &sd) == 0) {
166
+ seed = random_seed();
167
+ }
168
+ else {
169
+ seed = NUM2ULONG(sd);
170
+ }
171
+ old = rand_init(seed);
172
+
173
+ return ULONG2NUM(old);
174
+ }
175
+
176
+ /* - end of the code from ruby/random.c - */
177
+
178
+ #define genrand(y) \
179
+ { if (--left == 0) next_state();\
180
+ (y) = *next++;\
181
+ (y) ^= ((y) >> 11);\
182
+ (y) ^= ((y) << 7) & 0x9d2c5680UL;\
183
+ (y) ^= ((y) << 15) & 0xefc60000UL;\
184
+ (y) ^= ((y) >> 18); }
185
+
186
+ #define rand_double(x,y) \
187
+ (((double)((x)>>5)+(double)((y)>>6)*(1.0/67108864.0)) * (1.0/134217728.0))
188
+
189
+ #define rand_single(y) \
190
+ ((double)(y) * (1.0/4294967296.0))
191
+
192
+ static int n_bits(int64_t a)
193
+ {
194
+ int i, x, xl, n=8;
195
+ // int i, x, xu, xl, n=8;
196
+ int64_t m;
197
+
198
+ if (a==0) return 0;
199
+ if (a<0) a=-a;
200
+
201
+ x = ((int64_t)1)<<n;
202
+ // xu = 1<<(n+1);
203
+ xl = 0;
204
+
205
+ for (i=n; i>=0; --i) {
206
+ m = ~((((int64_t)1)<<(x-1))-1);
207
+
208
+ if (m & a) {
209
+ xl = x;
210
+ x += 1<<(i-1);
211
+ } else {
212
+ // xu = x;
213
+ x -= 1<<(i-1);
214
+ }
215
+ /* printf("%3i, [%3i, %3i], %x\n", i, xu, xl, m1); */
216
+ }
217
+ /* if (xu-xl!=1) printf("*** erorr %d - %d != 1\n", xu, xl); */
218
+ return xl;
219
+ }
220
+
221
+ // max&limit must be integer
222
+ static u_int64_t size_check(double rmax, double limit)
223
+ {
224
+ u_int64_t max;
225
+
226
+ if ( rmax == 0 ) {
227
+ return (u_int64_t)(limit-1);
228
+ }
229
+ if ( rmax < 0 ) {
230
+ rmax = -rmax;
231
+ }
232
+ max = (u_int64_t)(rmax - 1);
233
+ if ( max >= limit ) {
234
+ rb_raise(rb_eArgError, "rand-max(%.0f) must be <= %.0f", rmax, limit);
235
+ }
236
+ return max;
237
+ }
238
+
239
+ static void TpErr(void) {
240
+ rb_raise(rb_eTypeError,"illegal operation with this type");
241
+ }
242
+
243
+ static void RndB(int n, char *p1, int i1, double rmax)
244
+ {
245
+ u_int32_t y;
246
+ u_int64_t max;
247
+ int shift;
248
+
249
+ if ( rmax < 0 ) {
250
+ rb_raise(rb_eArgError, "rand-max must be positive");
251
+ }
252
+ max = size_check(rmax,0x100);
253
+ shift = 32 - n_bits(max);
254
+
255
+ if (max<1) {
256
+ for (; n; --n) {
257
+ *(u_int8_t*)p1 = 0;
258
+ p1+=i1;
259
+ }
260
+ } else {
261
+ for (; n; --n) {
262
+ do {
263
+ genrand(y);
264
+ y >>= shift;
265
+ } while (y > max);
266
+ *(u_int8_t*)p1 = (u_int8_t)y;
267
+ p1+=i1;
268
+ }
269
+ }
270
+ }
271
+
272
+ static void RndI(int n, char *p1, int i1, double rmax)
273
+ {
274
+ u_int32_t y;
275
+ u_int64_t max;
276
+ int shift, sign=1;
277
+
278
+ if ( rmax < 0 ) { rmax = -rmax; sign = -1; }
279
+ max = size_check(rmax,0x8000);
280
+ shift = 32 - n_bits(max);
281
+
282
+ if (max<1) {
283
+ for (; n; --n) {
284
+ *(int16_t*)p1 = 0;
285
+ p1+=i1;
286
+ }
287
+ } else {
288
+ for (; n; --n) {
289
+ do {
290
+ genrand(y);
291
+ y >>= shift;
292
+ } while (y > max);
293
+ *(int16_t*)p1 = (int16_t)y*sign;
294
+ p1+=i1;
295
+ }
296
+ }
297
+ }
298
+
299
+ static void RndL(int n, char *p1, int i1, double rmax)
300
+ {
301
+ u_int32_t y;
302
+ u_int64_t max;
303
+ int shift, sign=1;
304
+
305
+ if ( rmax < 0 ) { rmax = -rmax; sign = -1; }
306
+ max = size_check(rmax,0x80000000);
307
+ shift = 64 - n_bits(max);
308
+
309
+ if (max<1) {
310
+ for (; n; --n) {
311
+ *(int32_t*)p1 = 0;
312
+ p1+=i1;
313
+ }
314
+ } else {
315
+ for (; n; --n) {
316
+ do {
317
+ genrand(y);
318
+ y >>= shift;
319
+ } while (y > max);
320
+ *(int32_t*)p1 = (int32_t)y*sign;
321
+ p1+=i1;
322
+ }
323
+ }
324
+ }
325
+
326
+ static void RndG(int n, char *p1, int i1, double rmax)
327
+ {
328
+ u_int64_t y;
329
+ u_int64_t max;
330
+ int shift, sign=1;
331
+
332
+ if ( rmax < 0 ) { rmax = -rmax; sign = -1; }
333
+ max = size_check(rmax,0x800000000000);
334
+ shift = 64 - n_bits(max);
335
+
336
+ if (max<1) {
337
+ for (; n; --n) {
338
+ *(int64_t*)p1 = 0;
339
+ p1+=i1;
340
+ }
341
+ } else {
342
+ for (; n; --n) {
343
+ do {
344
+ genrand(y);
345
+ y >>= shift;
346
+ } while (y > max);
347
+ *(int64_t*)p1 = (int64_t)y*sign;
348
+ p1+=i1;
349
+ }
350
+ }
351
+ }
352
+
353
+ static void RndF(int n, char *p1, int i1, double rmax)
354
+ {
355
+ u_int32_t y;
356
+
357
+ for (; n; --n) {
358
+ genrand(y);
359
+ *(float*)p1 = rand_single(y) * rmax;
360
+ p1+=i1;
361
+ }
362
+ }
363
+
364
+ static void RndD(int n, char *p1, int i1, double rmax)
365
+ {
366
+ u_int32_t x,y;
367
+
368
+ for (; n; --n) {
369
+ genrand(x);
370
+ genrand(y);
371
+ *(double*)p1 = rand_double(x,y) * rmax;
372
+ p1+=i1;
373
+ }
374
+ }
375
+
376
+ static void RndX(int n, char *p1, int i1, double rmax)
377
+ {
378
+ u_int32_t y;
379
+
380
+ for (; n; --n) {
381
+ genrand(y);
382
+ ((scomplex*)p1)->r = rand_single(y) * rmax;
383
+ ((scomplex*)p1)->i = 0;
384
+ p1+=i1;
385
+ }
386
+ }
387
+
388
+ static void RndC(int n, char *p1, int i1, double rmax)
389
+ {
390
+ u_int32_t x,y;
391
+
392
+ for (; n; --n) {
393
+ genrand(x);
394
+ genrand(y);
395
+ ((dcomplex*)p1)->r = rand_double(x,y) * rmax;
396
+ ((dcomplex*)p1)->i = 0;
397
+ p1+=i1;
398
+ }
399
+ }
400
+
401
+ na_func_t RndFuncs =
402
+ { TpErr, RndB, RndI, RndL, RndG, RndF, RndD, RndX, RndC, TpErr };
403
+
404
+
405
+ static VALUE
406
+ na_random_bang(int argc, VALUE *argv, VALUE self)
407
+ {
408
+ VALUE vmax;
409
+ struct NARRAY *ary;
410
+ double rmax;
411
+
412
+ rb_scan_args(argc, argv, "01", &vmax);
413
+ if (first) {
414
+ rand_init(random_seed());
415
+ }
416
+ if (NIL_P(vmax)) {
417
+ rmax = 1;
418
+ } else {
419
+ rmax = NUM2DBL(vmax);
420
+ }
421
+ if (isinf(rmax) || isnan(rmax)) {
422
+ rb_raise(rb_eArgError, "rand-max must be regular value");
423
+ }
424
+
425
+ GetNArray(self,ary);
426
+
427
+ (*RndFuncs[ary->type])( ary->total, ary->ptr, na_sizeof[ary->type], rmax );
428
+
429
+ return self;
430
+ }
431
+
432
+ static VALUE
433
+ na_random(int argc, VALUE *argv, VALUE self)
434
+ {
435
+ return na_random_bang(argc, argv, na_clone(self));
436
+ }
437
+
438
+ void
439
+ Init_na_random()
440
+ {
441
+ rb_define_singleton_method(cNArray,"srand",na_s_srand,-1);
442
+ rb_define_method(cNArray, "random!", na_random_bang,-1);
443
+ rb_define_method(cNArray, "random", na_random,-1);
444
+ }