blob: cd2096c632ae89dc140c1dc9359223f17a4625ed [file] [log] [blame]
whrb973f2b2000-05-05 19:34:50 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
vapier45a8ba02009-07-20 10:59:32 +00003 *
whrb973f2b2000-05-05 19:34:50 +00004 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
vapier45a8ba02009-07-20 10:59:32 +00007 *
whrb973f2b2000-05-05 19:34:50 +00008 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
vapier45a8ba02009-07-20 10:59:32 +000011 *
whrb973f2b2000-05-05 19:34:50 +000012 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
vapier45a8ba02009-07-20 10:59:32 +000018 *
whrb973f2b2000-05-05 19:34:50 +000019 * You should have received a copy of the GNU General Public License along
Wanlong Gaofed96412012-10-24 10:10:29 +080020 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
vapier45a8ba02009-07-20 10:59:32 +000022 *
whrb973f2b2000-05-05 19:34:50 +000023 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
vapier45a8ba02009-07-20 10:59:32 +000025 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
whrb973f2b2000-05-05 19:34:50 +000030 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 */
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <malloc.h>
36#include "random_range.h"
37
38/*
39 * Internal format of the range array set up by parse_range()
40 */
41
42struct range {
Wanlong Gao354ebb42012-12-07 10:10:04 +080043 int min;
44 int max;
45 int mult;
whrb973f2b2000-05-05 19:34:50 +000046};
47
48/*
49 * parse_ranges() is a function to parse a comma-separated list of range
50 * tokens each having the following form:
51 *
52 * num
53 * or
54 * min:max[:mult]
55 *
56 * any of the values may be blank (ie. min::mult, :max, etc.) and default
57 * values for missing arguments may be supplied by the caller.
58 *
59 * The special first form is short hand for 'num:num'.
60 *
61 * After parsing the string, the ranges are put into an array of integers,
62 * which is malloc'd by the routine. The min, max, and mult entries of each
63 * range can be extracted from the array using the range_min(), range_max(),
64 * and range_mult() functions.
65 *
66 * It is the responsibility of the caller to free the space allocated by
67 * parse_ranges() - a single call to free() will free the space.
68 *
69 * str The string to parse - assumed to be a comma-separated
70 * list of tokens having the above format.
71 * defmin default value to plug in for min, if it is missing
vapier45a8ba02009-07-20 10:59:32 +000072 * defmax default value to plug in for max, if it is missing
whrb973f2b2000-05-05 19:34:50 +000073 * defmult default value to plug in for mult, if missing
74 * parse_func A user-supplied function pointer, which parse_ranges()
75 * can call to parse the min, max, and mult strings. This
76 * allows for customized number formats. The function
77 * MUST have the following prototype:
78 * parse_func(char *str, int *val)
79 * The function should return -1 if str cannot be parsed
vapier45a8ba02009-07-20 10:59:32 +000080 * into an integer, or >= 0 if it was successfully
whrb973f2b2000-05-05 19:34:50 +000081 * parsed. The resulting integer will be stored in
82 * *val. If parse_func is NULL, parse_ranges will parse
83 * the tokens in a manner consistent with the the sscanf
84 * %i format.
85 * range_ptr A user-supplied char **, which will be set to point
86 * at malloc'd space which holds the parsed range
87 * values. If range_ptr is NULL, parse_ranges() just
88 * parses the string. The data returned in range_ptr
89 * should not be processed directly - use the functions
90 * range_min(), range_max(), and range_mult() to access
91 * data for a given range.
92 * errptr user-supplied char ** which can be set to point to a
93 * static error string. If errptr is NULL, it is ignored.
94 *
95 * parse_range() returns -1 on error, or the number of ranges parsed.
96 */
97
Wanlong Gao354ebb42012-12-07 10:10:04 +080098static int str_to_int();
whrb973f2b2000-05-05 19:34:50 +000099static long long divider(long long, long long, long long, long long);
100
Wanlong Gao354ebb42012-12-07 10:10:04 +0800101int parse_ranges(str, defmin, defmax, defmult, parse_func, rangeptr, errptr)
102char *str;
103int defmin;
104int defmax;
105int defmult;
106int (*parse_func) ();
107char **rangeptr;
108char **errptr;
whrb973f2b2000-05-05 19:34:50 +0000109{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800110 int ncommas;
111 char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr;
112 struct range *rp, *ranges;
113 static char errmsg[256];
whrb973f2b2000-05-05 19:34:50 +0000114
115 if (errptr != NULL) {
116 *errptr = errmsg;
117 }
118
119 for (ncommas = 0, cp = str; *cp != '\0'; cp++) {
120 if (*cp == ',') {
121 ncommas++;
122 }
123 }
124
125 if (parse_func == NULL) {
126 parse_func = str_to_int;
127 }
128
129 tmpstr = strdup(str);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800130 ranges = (struct range *)malloc((ncommas + 1) * sizeof(struct range));
whrb973f2b2000-05-05 19:34:50 +0000131 rp = ranges;
132
133 tok = strtok(tmpstr, ",");
134 while (tok != NULL) {
135 n1str = tok;
136 n2str = NULL;
137 multstr = NULL;
138
139 rp->min = defmin;
140 rp->max = defmax;
141 rp->mult = defmult;
142
143 if ((cp = strchr(n1str, ':')) != NULL) {
144 *cp = '\0';
Wanlong Gao354ebb42012-12-07 10:10:04 +0800145 n2str = cp + 1;
whrb973f2b2000-05-05 19:34:50 +0000146
147 if ((cp = strchr(n2str, ':')) != NULL) {
148 *cp = '\0';
Wanlong Gao354ebb42012-12-07 10:10:04 +0800149 multstr = cp + 1;
whrb973f2b2000-05-05 19:34:50 +0000150 }
151 }
152
153 /*
154 * Parse the 'min' field - if it is zero length (:n2[:mult]
155 * format), retain the default value, otherwise, pass the
156 * string to the parse function.
157 */
158
159 if ((int)strlen(n1str) > 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800160 if ((*parse_func) (n1str, &rp->min) < 0) {
161 sprintf(errmsg,
162 "error parsing string %s into an integer",
163 n1str);
whrb973f2b2000-05-05 19:34:50 +0000164 free(tmpstr);
165 free(ranges);
166 return -1;
167 }
168 }
169
170 /*
171 * Process the 'max' field - if one was not present (n1 format)
vapier45a8ba02009-07-20 10:59:32 +0000172 * set max equal to min. If the field was present, but
whrb973f2b2000-05-05 19:34:50 +0000173 * zero length (n1: format), retain the default. Otherwise
174 * pass the string to the parse function.
175 */
176
177 if (n2str == NULL) {
178 rp->max = rp->min;
179 } else if ((int)strlen(n2str) > 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800180 if ((*parse_func) (n2str, &rp->max) < 0) {
181 sprintf(errmsg,
182 "error parsing string %s into an integer",
183 n2str);
whrb973f2b2000-05-05 19:34:50 +0000184 free(tmpstr);
185 free(ranges);
186 return -1;
187 }
188 }
189
190 /*
vapier45a8ba02009-07-20 10:59:32 +0000191 * Process the 'mult' field - if one was not present
whrb973f2b2000-05-05 19:34:50 +0000192 * (n1:n2 format), or the field was zero length (n1:n2: format)
193 * then set the mult field to defmult - otherwise pass then
194 * mult field to the parse function.
195 */
196
197 if (multstr != NULL && (int)strlen(multstr) > 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800198 if ((*parse_func) (multstr, &rp->mult) < 0) {
199 sprintf(errmsg,
200 "error parsing string %s into an integer",
201 multstr);
whrb973f2b2000-05-05 19:34:50 +0000202 free(tmpstr);
203 free(ranges);
204 return -1;
205 }
206 }
207
208 rp++;
209 tok = strtok(NULL, ",");
210 }
211
212 free(tmpstr);
213
214 if (rangeptr != NULL) {
215 *rangeptr = (char *)ranges;
216 } else {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800217 free(ranges); /* just running in parse mode */
whrb973f2b2000-05-05 19:34:50 +0000218 }
219
220 return (rp - ranges);
221}
222
223/*
224 * The default integer-parsing function
225 */
226
Wanlong Gao354ebb42012-12-07 10:10:04 +0800227static int str_to_int(str, ip)
228char *str;
229int *ip;
whrb973f2b2000-05-05 19:34:50 +0000230{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800231 char c;
whrb973f2b2000-05-05 19:34:50 +0000232
233 if (sscanf(str, "%i%c", ip, &c) != 1) {
234 return -1;
235 } else {
236 return 0;
237 }
238}
239
240/*
241 * Three simple functions to return the min, max, and mult values for a given
242 * range. It is assumed that rbuf is a range buffer set up by parse_ranges(),
243 * and that r is a valid range within that buffer.
244 */
245
Wanlong Gao354ebb42012-12-07 10:10:04 +0800246int range_min(rbuf, r)
247char *rbuf;
248int r;
whrb973f2b2000-05-05 19:34:50 +0000249{
250 return ((struct range *)rbuf)[r].min;
251}
252
Wanlong Gao354ebb42012-12-07 10:10:04 +0800253int range_max(rbuf, r)
254char *rbuf;
255int r;
whrb973f2b2000-05-05 19:34:50 +0000256{
257 return ((struct range *)rbuf)[r].max;
258}
259
Wanlong Gao354ebb42012-12-07 10:10:04 +0800260int range_mult(rbuf, r)
261char *rbuf;
262int r;
whrb973f2b2000-05-05 19:34:50 +0000263{
264 return ((struct range *)rbuf)[r].mult;
265}
266
267/*****************************************************************************
268 * random_range(int start, int end, int mult, char **errp)
269 *
270 * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple
271 * of 'mult'. Start and end may be any valid integer, but mult must be an
272 * integer > 0. errp is a char ** which will be set to point to a static
273 * error message buffer if it is not NULL, and an error occurs.
274 *
275 * The errp is the only way to check if the routine fails - currently the only
276 * failure conditions are:
277 *
278 * mult < 1
279 * no numbers in the start-end range that are a multiple of 'mult'
280 *
281 * If random_range_fails, and errp is a valid pointer, it will point to an
282 * internal error buffer. If errp is a vaild pointer, and random_range
283 * is successful, errp will be set to NULL.
284 *
285 * Note - if mult is 1 (the most common case), there are error conditions
286 * possible, and errp need not be used.
287 *
288 * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when
289 * setting the seed.
290 *****************************************************************************/
291
Wanlong Gao354ebb42012-12-07 10:10:04 +0800292long random_range(min, max, mult, errp)
293int min;
294int max;
295int mult;
296char **errp;
whrb973f2b2000-05-05 19:34:50 +0000297{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800298 int r, nmults, orig_min, orig_max, orig_mult, tmp;
299 extern long lrand48();
300 static char errbuf[128];
whrb973f2b2000-05-05 19:34:50 +0000301
302 /*
303 * Sanity check
304 */
305
306 if (mult < 1) {
307 if (errp != NULL) {
308 sprintf(errbuf, "mult arg must be greater than 0");
309 *errp = errbuf;
310 }
311 return -1;
312 }
313
314 /*
315 * Save original parameter values for use in error message
316 */
317
318 orig_min = min;
319 orig_max = max;
320 orig_mult = mult;
321
322 /*
323 * switch min/max if max < min
324 */
325
326 if (max < min) {
327 tmp = max;
328 max = min;
329 min = tmp;
330 }
331
332 /*
333 * select the random number
334 */
335
Wanlong Gao354ebb42012-12-07 10:10:04 +0800336 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
337 min += mult - r;
whrb973f2b2000-05-05 19:34:50 +0000338
Wanlong Gao354ebb42012-12-07 10:10:04 +0800339 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
340 max -= r;
whrb973f2b2000-05-05 19:34:50 +0000341
Wanlong Gao354ebb42012-12-07 10:10:04 +0800342 if (min > max) { /* no 'mult' multiples between min & max */
whrb973f2b2000-05-05 19:34:50 +0000343 if (errp != NULL) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800344 sprintf(errbuf,
345 "no numbers in the range %d:%d that are a multiple of %d",
346 orig_min, orig_max, orig_mult);
whrb973f2b2000-05-05 19:34:50 +0000347 *errp = errbuf;
348 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800349 return -1;
whrb973f2b2000-05-05 19:34:50 +0000350 }
351
352 if (errp != NULL) {
353 *errp = NULL;
354 }
355
Wanlong Gao354ebb42012-12-07 10:10:04 +0800356 nmults = ((max - min) / mult) + 1;
vapier45a8ba02009-07-20 10:59:32 +0000357#if CRAY
Wanlong Gao354ebb42012-12-07 10:10:04 +0800358 /*
359 * If max is less than 2gb, then the value can fit in 32 bits
360 * and the standard lrand48() routine can be used.
361 */
362 if (max <= (long)2147483647) {
363 return (long)(min + (((long)lrand48() % nmults) * mult));
364 } else {
365 /*
366 * max is greater than 2gb - meeds more than 32 bits.
367 * Since lrand48 only will get a number up to 32bits.
368 */
369 long randnum;
370 randnum = divider(min, max, 0, -1);
371 return (long)(min + ((randnum % nmults) * mult));
372 }
whrb973f2b2000-05-05 19:34:50 +0000373
374#else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800375 return (min + ((lrand48() % nmults) * mult));
whrb973f2b2000-05-05 19:34:50 +0000376#endif
377
378}
379
380/*
381 * Just like random_range, but all values are longs.
382 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800383long random_rangel(min, max, mult, errp)
384long min;
385long max;
386long mult;
387char **errp;
whrb973f2b2000-05-05 19:34:50 +0000388{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800389 long r, nmults, orig_min, orig_max, orig_mult, tmp;
390 extern long lrand48();
391 static char errbuf[128];
whrb973f2b2000-05-05 19:34:50 +0000392
393 /*
394 * Sanity check
395 */
396
397 if (mult < 1) {
398 if (errp != NULL) {
399 sprintf(errbuf, "mult arg must be greater than 0");
400 *errp = errbuf;
401 }
402 return -1;
403 }
404
405 /*
406 * Save original parameter values for use in error message
407 */
408
409 orig_min = min;
410 orig_max = max;
411 orig_mult = mult;
412
413 /*
414 * switch min/max if max < min
415 */
416
417 if (max < min) {
418 tmp = max;
419 max = min;
420 min = tmp;
421 }
422
423 /*
424 * select the random number
425 */
426
Wanlong Gao354ebb42012-12-07 10:10:04 +0800427 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
428 min += mult - r;
whrb973f2b2000-05-05 19:34:50 +0000429
Wanlong Gao354ebb42012-12-07 10:10:04 +0800430 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
431 max -= r;
whrb973f2b2000-05-05 19:34:50 +0000432
Wanlong Gao354ebb42012-12-07 10:10:04 +0800433 if (min > max) { /* no 'mult' multiples between min & max */
whrb973f2b2000-05-05 19:34:50 +0000434 if (errp != NULL) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800435 sprintf(errbuf,
436 "no numbers in the range %ld:%ld that are a multiple of %ld",
437 orig_min, orig_max, orig_mult);
438 *errp = errbuf;
whrb973f2b2000-05-05 19:34:50 +0000439 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800440 return -1;
whrb973f2b2000-05-05 19:34:50 +0000441 }
442
443 if (errp != NULL) {
444 *errp = NULL;
445 }
446
Wanlong Gao354ebb42012-12-07 10:10:04 +0800447 nmults = ((max - min) / mult) + 1;
whrb973f2b2000-05-05 19:34:50 +0000448#if CRAY || (_MIPS_SZLONG == 64)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800449 /*
450 * If max is less than 2gb, then the value can fit in 32 bits
451 * and the standard lrand48() routine can be used.
452 */
453 if (max <= (long)2147483647) {
454 return (long)(min + (((long)lrand48() % nmults) * mult));
455 } else {
456 /*
457 * max is greater than 2gb - meeds more than 32 bits.
458 * Since lrand48 only will get a number up to 32bits.
459 */
460 long randnum;
461 randnum = divider(min, max, 0, -1);
462 return (long)(min + ((randnum % nmults) * mult));
463 }
whrb973f2b2000-05-05 19:34:50 +0000464
465#else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800466 return (min + ((lrand48() % nmults) * mult));
whrb973f2b2000-05-05 19:34:50 +0000467#endif
468}
469
470/*
471 * Attempts to be just like random_range, but everything is long long (64 bit)
472 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800473long long random_rangell(min, max, mult, errp)
474long long min;
475long long max;
476long long mult;
477char **errp;
whrb973f2b2000-05-05 19:34:50 +0000478{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800479 long long r, nmults, orig_min, orig_max, orig_mult, tmp;
480 long long randnum;
481 extern long lrand48();
482 static char errbuf[128];
whrb973f2b2000-05-05 19:34:50 +0000483
484 /*
485 * Sanity check
486 */
487
488 if (mult < 1) {
489 if (errp != NULL) {
490 sprintf(errbuf, "mult arg must be greater than 0");
491 *errp = errbuf;
492 }
493 return -1;
494 }
495
496 /*
497 * Save original parameter values for use in error message
498 */
499
500 orig_min = min;
501 orig_max = max;
502 orig_mult = mult;
503
504 /*
505 * switch min/max if max < min
506 */
507
508 if (max < min) {
509 tmp = max;
510 max = min;
511 min = tmp;
512 }
513
514 /*
515 * select the random number
516 */
517
Wanlong Gao354ebb42012-12-07 10:10:04 +0800518 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
519 min += mult - r;
whrb973f2b2000-05-05 19:34:50 +0000520
Wanlong Gao354ebb42012-12-07 10:10:04 +0800521 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
522 max -= r;
whrb973f2b2000-05-05 19:34:50 +0000523
Wanlong Gao354ebb42012-12-07 10:10:04 +0800524 if (min > max) { /* no 'mult' multiples between min & max */
whrb973f2b2000-05-05 19:34:50 +0000525 if (errp != NULL) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800526 sprintf(errbuf,
527 "no numbers in the range %lld:%lld that are a multiple of %lld",
528 orig_min, orig_max, orig_mult);
529 *errp = errbuf;
whrb973f2b2000-05-05 19:34:50 +0000530 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800531 return -1;
whrb973f2b2000-05-05 19:34:50 +0000532 }
533
534 if (errp != NULL) {
535 *errp = NULL;
536 }
537
Wanlong Gao354ebb42012-12-07 10:10:04 +0800538 nmults = ((max - min) / mult) + 1;
539 /*
whrb973f2b2000-05-05 19:34:50 +0000540 * If max is less than 2gb, then the value can fit in 32 bits
541 * and the standard lrand48() routine can be used.
542 */
Garrett Cooper903910d2010-11-23 09:27:44 -0800543 if (max <= (long)2147483647) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800544 return (long long)(min +
545 (((long long)lrand48() % nmults) * mult));
whrb973f2b2000-05-05 19:34:50 +0000546 } else {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800547 /*
548 * max is greater than 2gb - meeds more than 32 bits.
549 * Since lrand48 only will get a number up to 32bits.
550 */
551 randnum = divider(min, max, 0, -1);
552 return (long long)(min + ((randnum % nmults) * mult));
553 }
whrb973f2b2000-05-05 19:34:50 +0000554
555}
556
557/*
558 * This functional will recusively call itself to return a random
559 * number min and max. It was designed to work the 64bit numbers
560 * even when compiled as 32 bit process.
561 * algorithm: to use the official lrand48() routine - limited to 32 bits.
562 * find the difference between min and max (max-min).
563 * if the difference is 2g or less, use the random number gotton from lrand48().
564 * Determine the midway point between min and max.
565 * if the midway point is less than 2g from min or max,
566 * randomly add the random number gotton from lrand48() to
567 * either min or the midpoint.
568 * Otherwise, call outself with min and max being min and midway value or
569 * midway value and max. This will reduce the range in half.
570 */
571static long long
572divider(long long min, long long max, long long cnt, long long rand)
573{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800574 long long med, half, diff;
whrb973f2b2000-05-05 19:34:50 +0000575
Wanlong Gao354ebb42012-12-07 10:10:04 +0800576 /*
577 * prevent run away code. We are dividing by two each count.
578 * if we get to a count of more than 32, we should have gotten
579 * to 2gb.
580 */
581 if (cnt > 32)
582 return -1;
whrb973f2b2000-05-05 19:34:50 +0000583
Wanlong Gao354ebb42012-12-07 10:10:04 +0800584 /*
585 * Only get a random number the first time.
586 */
587 if (cnt == 0 || rand < -1) {
588 rand = (long long)lrand48(); /* 32 bit random number */
whrb973f2b2000-05-05 19:34:50 +0000589 }
vapier45a8ba02009-07-20 10:59:32 +0000590
Wanlong Gao354ebb42012-12-07 10:10:04 +0800591 diff = max - min;
592
593 if (diff <= 2147483647)
594 return min + rand;
595
596 half = diff / (long long)2; /* half the distance between min and max */
597 med = min + half; /* med way point between min and max */
598
599#if DEBUG
600 printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max,
601 cnt, rand);
602 printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med);
603#endif
604
605 if (half <= 2147483647) {
606 /*
607 * If half is smaller than 2gb, we can use the random number
608 * to pick the number within the min to med or med to max
609 * if the cnt bit of rand is zero or one, respectively.
610 */
611 if (rand & (1 << cnt))
612 return med + rand;
613 else
614 return min + rand;
615 } else {
616 /*
617 * recursively call ourself to reduce the value to the bottom half
618 * or top half (bit cnt is set).
619 */
620 if (rand & (1 << cnt)) {
621 return divider(med, max, cnt + 1, rand);
622 } else {
623 return divider(min, med, cnt + 1, rand);
624 }
625
626 }
whrb973f2b2000-05-05 19:34:50 +0000627
628}
629
whrb973f2b2000-05-05 19:34:50 +0000630/*****************************************************************************
631 * random_range_seed(s)
632 *
633 * Sets the random seed to s. Uses srand48(), assuming that lrand48() will
634 * be used in random_range().
635 *****************************************************************************/
636
Wanlong Gao354ebb42012-12-07 10:10:04 +0800637void random_range_seed(s)
638long s;
whrb973f2b2000-05-05 19:34:50 +0000639{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800640 extern void srand48();
whrb973f2b2000-05-05 19:34:50 +0000641
Wanlong Gao354ebb42012-12-07 10:10:04 +0800642 srand48(s);
whrb973f2b2000-05-05 19:34:50 +0000643}
644
645/****************************************************************************
646 * random_bit(mask)
647 *
648 * This function randomly returns a single bit from the bits
649 * set in mask. If mask is zero, zero is returned.
650 *
651 ****************************************************************************/
Wanlong Gao354ebb42012-12-07 10:10:04 +0800652long random_bit(long mask)
whrb973f2b2000-05-05 19:34:50 +0000653{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800654 int nbits = 0; /* number of set bits in mask */
655 long bit; /* used to count bits and num of set bits choosen */
656 int nshift; /* used to count bit shifts */
whrb973f2b2000-05-05 19:34:50 +0000657
Wanlong Gao354ebb42012-12-07 10:10:04 +0800658 if (mask == 0)
659 return 0;
whrb973f2b2000-05-05 19:34:50 +0000660
Wanlong Gao354ebb42012-12-07 10:10:04 +0800661 /*
662 * get the number of bits set in mask
663 */
whrb973f2b2000-05-05 19:34:50 +0000664#ifndef CRAY
665
Wanlong Gao354ebb42012-12-07 10:10:04 +0800666 bit = 1L;
667 for (nshift = 0; (unsigned int)nshift < sizeof(long) * 8; nshift++) {
668 if (mask & bit)
669 nbits++;
670 bit = bit << 1;
671 }
whrb973f2b2000-05-05 19:34:50 +0000672
673#else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800674 nbits = _popcnt(mask);
675#endif /* if CRAY */
whrb973f2b2000-05-05 19:34:50 +0000676
Wanlong Gao354ebb42012-12-07 10:10:04 +0800677 /*
678 * randomly choose a bit.
679 */
680 bit = random_range(1, nbits, 1, NULL);
whrb973f2b2000-05-05 19:34:50 +0000681
Wanlong Gao354ebb42012-12-07 10:10:04 +0800682 /*
683 * shift bits until you determine which bit was randomly choosen.
684 * nshift will hold the number of shifts to make.
685 */
whrb973f2b2000-05-05 19:34:50 +0000686
Wanlong Gao354ebb42012-12-07 10:10:04 +0800687 nshift = 0;
688 while (bit) {
689 /* check if the current one's bit is set */
690 if (mask & 1L) {
691 bit--;
692 }
693 mask = mask >> 1;
694 nshift++;
695 }
whrb973f2b2000-05-05 19:34:50 +0000696
Wanlong Gao354ebb42012-12-07 10:10:04 +0800697 return 01L << (nshift - 1);
whrb973f2b2000-05-05 19:34:50 +0000698
699}
700
whrb973f2b2000-05-05 19:34:50 +0000701#if RANDOM_BIT_UNITTEST
702/*
703 * The following is a unit test main function for random_bit().
704 */
705main(argc, argv)
706int argc;
707char **argv;
708{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800709 int ind;
710 int cnt, iter;
711 long mask, ret;
whrb973f2b2000-05-05 19:34:50 +0000712
Wanlong Gao354ebb42012-12-07 10:10:04 +0800713 printf("test for first and last bit set\n");
714 mask = 1L;
715 ret = random_bit(mask);
716 printf("random_bit(%#o) returned %#o\n", mask, ret);
whrb973f2b2000-05-05 19:34:50 +0000717
Wanlong Gao354ebb42012-12-07 10:10:04 +0800718 mask = 1L << (sizeof(long) * 8 - 1);
719 ret = random_bit(mask);
720 printf("random_bit(%#o) returned %#o\n", mask, ret);
whrb973f2b2000-05-05 19:34:50 +0000721
Wanlong Gao354ebb42012-12-07 10:10:04 +0800722 if (argc >= 3) {
723 iter = atoi(argv[1]);
724 for (ind = 2; ind < argc; ind++) {
725 printf("Calling random_bit %d times for mask %#o\n",
726 iter, mask);
727 sscanf(argv[ind], "%i", &mask);
728 for (cnt = 0; cnt < iter; cnt++) {
729 ret = random_bit(mask);
730 printf("random_bit(%#o) returned %#o\n", mask,
731 ret);
732 }
733 }
734 }
735 exit(0);
whrb973f2b2000-05-05 19:34:50 +0000736}
737
738#endif /* end if RANDOM_BIT_UNITTEST */
739
whrb973f2b2000-05-05 19:34:50 +0000740#if UNIT_TEST
741/*
742 * The following is a unit test main function for random_range*().
743 */
744
Wanlong Gao354ebb42012-12-07 10:10:04 +0800745#define PARTNUM 10 /* used to determine even distribution of random numbers */
whrb973f2b2000-05-05 19:34:50 +0000746#define MEG 1024*1024*1024
747#define GIG 1073741824
Wanlong Gao354ebb42012-12-07 10:10:04 +0800748int main(argc, argv)
whrb973f2b2000-05-05 19:34:50 +0000749int argc;
750char **argv;
751{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800752 int ind;
753 int cnt, iter = 10;
754 int imin = 0, imult = 1, itmin, itmax = 0;
whrb973f2b2000-05-05 19:34:50 +0000755#if CRAY
Wanlong Gao354ebb42012-12-07 10:10:04 +0800756 int imax = 6 * GIG; /* higher than 32 bits */
whrb973f2b2000-05-05 19:34:50 +0000757#else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800758 int imax = 1048576;
whrb973f2b2000-05-05 19:34:50 +0000759#endif
760
Wanlong Gao354ebb42012-12-07 10:10:04 +0800761 long lret, lmin = 0, lmult = 1, ltmin, ltmax = 0;
whrb973f2b2000-05-05 19:34:50 +0000762#if CRAY || (_MIPS_SZLONG == 64)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800763 long lmax = 6 * (long)GIG; /* higher than 32 bits */
whrb973f2b2000-05-05 19:34:50 +0000764#else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800765 long lmax = 1048576;
whrb973f2b2000-05-05 19:34:50 +0000766#endif
Wanlong Gao354ebb42012-12-07 10:10:04 +0800767 long long llret, llmin = 0, llmult = 1, lltmin, lltmax = 0;
768 long long llmax = (long long)80 * (long long)GIG;
whrb973f2b2000-05-05 19:34:50 +0000769
Wanlong Gao354ebb42012-12-07 10:10:04 +0800770 long part;
771 long long lpart;
772 long cntarr[PARTNUM];
773 long valbound[PARTNUM];
774 long long lvalbound[PARTNUM];
whrb973f2b2000-05-05 19:34:50 +0000775
Wanlong Gao354ebb42012-12-07 10:10:04 +0800776 for (ind = 0; ind < PARTNUM; ind++)
777 cntarr[ind] = 0;
vapier45a8ba02009-07-20 10:59:32 +0000778
Wanlong Gao354ebb42012-12-07 10:10:04 +0800779 if (argc < 2) {
780 printf("Usage: %s func [iterations] \n", argv[0]);
781 printf
782 ("func can be random_range, random_rangel, random_rangell\n");
783 exit(1);
784 }
whrb973f2b2000-05-05 19:34:50 +0000785
Wanlong Gao354ebb42012-12-07 10:10:04 +0800786 if (argc >= 3) {
787 if (sscanf(argv[2], "%i", &iter) != 1) {
788 printf("Usage: %s [func iterations] \n", argv[0]);
789 printf("argv[2] is not a number\n");
790 exit(1);
whrb973f2b2000-05-05 19:34:50 +0000791 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800792 }
whrb973f2b2000-05-05 19:34:50 +0000793
whrb973f2b2000-05-05 19:34:50 +0000794 /*
Wanlong Gao354ebb42012-12-07 10:10:04 +0800795 * random_rangel ()
796 */
797 if (strcmp(argv[1], "random_rangel") == 0) {
798 ltmin = lmax;
799 part = lmax / PARTNUM;
800 for (ind = 0; ind < PARTNUM; ind++) {
801 valbound[ind] = part * ind;
whrb973f2b2000-05-05 19:34:50 +0000802 }
whrb973f2b2000-05-05 19:34:50 +0000803
Wanlong Gao354ebb42012-12-07 10:10:04 +0800804 for (cnt = 0; cnt < iter; cnt++) {
805 lret = random_rangel(lmin, lmax, lmult, NULL);
806 if (iter < 100)
807 printf("%ld\n", lret);
808 if (lret < ltmin)
809 ltmin = lret;
810 if (lret > ltmax)
811 ltmax = lret;
812 for (ind = 0; ind < PARTNUM - 1; ind++) {
813 if (valbound[ind] < lret
814 && lret <= valbound[ind + 1]) {
815 cntarr[ind]++;
816 break;
817 }
818 }
819 if (lret > valbound[PARTNUM - 1]) {
820 cntarr[PARTNUM - 1]++;
821 }
822 }
823 for (ind = 0; ind < PARTNUM - 1; ind++) {
824 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1,
825 valbound[ind], valbound[ind + 1], cntarr[ind],
826 (float)(cntarr[ind] / (float)iter));
827 }
828 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
829 valbound[PARTNUM - 1], lmax, cntarr[PARTNUM - 1],
830 (float)(cntarr[PARTNUM - 1] / (float)iter));
831 printf(" min=%ld, max=%ld\n", ltmin, ltmax);
whrb973f2b2000-05-05 19:34:50 +0000832
Wanlong Gao354ebb42012-12-07 10:10:04 +0800833 } else if (strcmp(argv[1], "random_rangell") == 0) {
834 /*
835 * random_rangell() unit test
836 */
837 lltmin = llmax;
838 lpart = llmax / PARTNUM;
839 for (ind = 0; ind < PARTNUM; ind++) {
840 lvalbound[ind] = (long long)(lpart * ind);
841 }
842
843 for (cnt = 0; cnt < iter; cnt++) {
844 llret = random_rangell(llmin, llmax, llmult, NULL);
845 if (iter < 100)
846 printf("random_rangell returned %lld\n", llret);
847 if (llret < lltmin)
848 lltmin = llret;
849 if (llret > lltmax)
850 lltmax = llret;
851
852 for (ind = 0; ind < PARTNUM - 1; ind++) {
853 if (lvalbound[ind] < llret
854 && llret <= lvalbound[ind + 1]) {
855 cntarr[ind]++;
856 break;
857 }
858 }
859 if (llret > lvalbound[PARTNUM - 1]) {
860 cntarr[PARTNUM - 1]++;
861 }
862 }
863 for (ind = 0; ind < PARTNUM - 1; ind++) {
864 printf("%2d %-13lld to %-13lld %5ld %4.4f\n",
865 ind + 1, lvalbound[ind], lvalbound[ind + 1],
866 cntarr[ind], (float)(cntarr[ind] / (float)iter));
867 }
868 printf("%2d %-13lld to %-13lld %5ld %4.4f\n", PARTNUM,
869 lvalbound[PARTNUM - 1], llmax, cntarr[PARTNUM - 1],
870 (float)(cntarr[PARTNUM - 1] / (float)iter));
871 printf(" min=%lld, max=%lld\n", lltmin, lltmax);
872
873 } else {
874 /*
875 * random_range() unit test
876 */
877 itmin = imax;
878 part = imax / PARTNUM;
879 for (ind = 0; ind < PARTNUM; ind++) {
880 valbound[ind] = part * ind;
881 }
882
883 for (cnt = 0; cnt < iter; cnt++) {
884 lret = random_range(imin, imax, imult, NULL);
885 if (iter < 100)
886 printf("%ld\n", lret);
887 if (lret < itmin)
888 itmin = lret;
889 if (lret > itmax)
890 itmax = lret;
891
892 for (ind = 0; ind < PARTNUM - 1; ind++) {
893 if (valbound[ind] < lret
894 && lret <= valbound[ind + 1]) {
895 cntarr[ind]++;
896 break;
897 }
898 }
899 if (lret > valbound[PARTNUM - 1]) {
900 cntarr[PARTNUM - 1]++;
901 }
902 }
903 for (ind = 0; ind < PARTNUM - 1; ind++) {
904 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1,
905 valbound[ind], valbound[ind + 1], cntarr[ind],
906 (float)(cntarr[ind] / (float)iter));
907 }
908 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
909 valbound[PARTNUM - 1], (long)imax, cntarr[PARTNUM - 1],
910 (float)(cntarr[PARTNUM - 1] / (float)iter));
911 printf(" min=%d, max=%d\n", itmin, itmax);
912
913 }
914
915 exit(0);
whrb973f2b2000-05-05 19:34:50 +0000916}
917
Chris Dearmanec6edca2012-10-17 19:54:01 -0700918#endif