2 * Copyright (c) 2000 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "random_range.h"
25 * Internal format of the range array set up by parse_range()
35 * parse_ranges() is a function to parse a comma-separated list of range
36 * tokens each having the following form:
42 * any of the values may be blank (ie. min::mult, :max, etc.) and default
43 * values for missing arguments may be supplied by the caller.
45 * The special first form is short hand for 'num:num'.
47 * After parsing the string, the ranges are put into an array of integers,
48 * which is malloc'd by the routine. The min, max, and mult entries of each
49 * range can be extracted from the array using the range_min(), range_max(),
50 * and range_mult() functions.
52 * It is the responsibility of the caller to free the space allocated by
53 * parse_ranges() - a single call to free() will free the space.
55 * str The string to parse - assumed to be a comma-separated
56 * list of tokens having the above format.
57 * defmin default value to plug in for min, if it is missing
58 * defmax default value to plug in for max, if it is missing
59 * defmult default value to plug in for mult, if missing
60 * parse_func A user-supplied function pointer, which parse_ranges()
61 * can call to parse the min, max, and mult strings. This
62 * allows for customized number formats. The function
63 * MUST have the following prototype:
64 * parse_func(char *str, int *val)
65 * The function should return -1 if str cannot be parsed
66 * into an integer, or >= 0 if it was successfully
67 * parsed. The resulting integer will be stored in
68 * *val. If parse_func is NULL, parse_ranges will parse
69 * the tokens in a manner consistent with the the sscanf
71 * range_ptr A user-supplied char **, which will be set to point
72 * at malloc'd space which holds the parsed range
73 * values. If range_ptr is NULL, parse_ranges() just
74 * parses the string. The data returned in range_ptr
75 * should not be processed directly - use the functions
76 * range_min(), range_max(), and range_mult() to access
77 * data for a given range.
78 * errptr user-supplied char ** which can be set to point to a
79 * static error string. If errptr is NULL, it is ignored.
81 * parse_range() returns -1 on error, or the number of ranges parsed.
84 static int str_to_int();
85 static long long divider(long long, long long, long long, long long);
88 parse_ranges(str, defmin, defmax, defmult, parse_func, rangeptr, errptr)
98 char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr;
99 struct range *rp, *ranges;
100 static char errmsg[256];
102 if (errptr != NULL) {
106 for (ncommas = 0, cp = str; *cp != '\0'; cp++) {
112 if (parse_func == NULL) {
113 parse_func = str_to_int;
116 tmpstr = strdup(str);
117 ranges = (struct range *)malloc((ncommas+1) * sizeof(struct range));
120 tok = strtok(tmpstr, ",");
121 while (tok != NULL) {
130 if ((cp = strchr(n1str, ':')) != NULL) {
134 if ((cp = strchr(n2str, ':')) != NULL) {
141 * Parse the 'min' field - if it is zero length (:n2[:mult]
142 * format), retain the default value, otherwise, pass the
143 * string to the parse function.
146 if ((int)strlen(n1str) > 0) {
147 if ((*parse_func)(n1str, &rp->min) < 0) {
148 sprintf(errmsg, "error parsing string %s into an integer", n1str);
156 * Process the 'max' field - if one was not present (n1 format)
157 * set max equal to min. If the field was present, but
158 * zero length (n1: format), retain the default. Otherwise
159 * pass the string to the parse function.
164 } else if ((int)strlen(n2str) > 0) {
165 if ((*parse_func)(n2str, &rp->max) < 0) {
166 sprintf(errmsg, "error parsing string %s into an integer", n2str);
174 * Process the 'mult' field - if one was not present
175 * (n1:n2 format), or the field was zero length (n1:n2: format)
176 * then set the mult field to defmult - otherwise pass then
177 * mult field to the parse function.
180 if (multstr != NULL && (int)strlen(multstr) > 0) {
181 if ((*parse_func)(multstr, &rp->mult) < 0) {
182 sprintf(errmsg, "error parsing string %s into an integer", multstr);
190 tok = strtok(NULL, ",");
195 if (rangeptr != NULL) {
196 *rangeptr = (char *)ranges;
198 free(ranges); /* just running in parse mode */
201 return (rp - ranges);
205 * The default integer-parsing function
215 if (sscanf(str, "%i%c", ip, &c) != 1) {
223 * Three simple functions to return the min, max, and mult values for a given
224 * range. It is assumed that rbuf is a range buffer set up by parse_ranges(),
225 * and that r is a valid range within that buffer.
233 return ((struct range *)rbuf)[r].min;
241 return ((struct range *)rbuf)[r].max;
249 return ((struct range *)rbuf)[r].mult;
252 /*****************************************************************************
253 * random_range(int start, int end, int mult, char **errp)
255 * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple
256 * of 'mult'. Start and end may be any valid integer, but mult must be an
257 * integer > 0. errp is a char ** which will be set to point to a static
258 * error message buffer if it is not NULL, and an error occurs.
260 * The errp is the only way to check if the routine fails - currently the only
261 * failure conditions are:
264 * no numbers in the start-end range that are a multiple of 'mult'
266 * If random_range_fails, and errp is a valid pointer, it will point to an
267 * internal error buffer. If errp is a vaild pointer, and random_range
268 * is successful, errp will be set to NULL.
270 * Note - if mult is 1 (the most common case), there are error conditions
271 * possible, and errp need not be used.
273 * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when
275 *****************************************************************************/
278 random_range(min, max, mult, errp)
284 int r, nmults, orig_min, orig_max, orig_mult, tmp;
285 extern long lrand48();
286 static char errbuf[128];
294 sprintf(errbuf, "mult arg must be greater than 0");
301 * Save original parameter values for use in error message
309 * switch min/max if max < min
319 * select the random number
322 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
325 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
328 if (min > max) { /* no 'mult' multiples between min & max */
330 sprintf(errbuf, "no numbers in the range %d:%d that are a multiple of %d", orig_min, orig_max, orig_mult);
340 nmults = ((max - min) / mult) + 1;
343 * If max is less than 2gb, then the value can fit in 32 bits
344 * and the standard lrand48() routine can be used.
346 if ( max <= (long)2147483647 ) {
347 return (long) (min + (((long)lrand48() % nmults) * mult));
350 * max is greater than 2gb - meeds more than 32 bits.
351 * Since lrand48 only will get a number up to 32bits.
354 randnum=divider(min, max, 0, -1);
355 return (long) (min + ((randnum % nmults) * mult));
359 return (min + ((lrand48() % nmults) * mult));
365 * Just like random_range, but all values are longs.
368 random_rangel(min, max, mult, errp)
374 long r, nmults, orig_min, orig_max, orig_mult, tmp;
375 extern long lrand48();
376 static char errbuf[128];
384 sprintf(errbuf, "mult arg must be greater than 0");
391 * Save original parameter values for use in error message
399 * switch min/max if max < min
409 * select the random number
412 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
415 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
418 if (min > max) { /* no 'mult' multiples between min & max */
421 "no numbers in the range %ld:%ld that are a multiple of %ld",
422 orig_min, orig_max, orig_mult);
432 nmults = ((max - min) / mult) + 1;
433 #if CRAY || (_MIPS_SZLONG == 64)
435 * If max is less than 2gb, then the value can fit in 32 bits
436 * and the standard lrand48() routine can be used.
438 if ( max <= (long)2147483647 ) {
439 return (long) (min + (((long)lrand48() % nmults) * mult));
442 * max is greater than 2gb - meeds more than 32 bits.
443 * Since lrand48 only will get a number up to 32bits.
446 randnum=divider(min, max, 0, -1);
447 return (long) (min + ((randnum % nmults) * mult));
451 return (min + ((lrand48() % nmults) * mult));
456 * Attempts to be just like random_range, but everything is long long (64 bit)
459 random_rangell(min, max, mult, errp)
465 long long r, nmults, orig_min, orig_max, orig_mult, tmp;
467 extern long lrand48();
468 static char errbuf[128];
476 sprintf(errbuf, "mult arg must be greater than 0");
483 * Save original parameter values for use in error message
491 * switch min/max if max < min
501 * select the random number
504 if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
507 if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
510 if (min > max) { /* no 'mult' multiples between min & max */
513 "no numbers in the range %lld:%lld that are a multiple of %lld",
514 orig_min, orig_max, orig_mult);
524 nmults = ((max - min) / mult) + 1;
526 * If max is less than 2gb, then the value can fit in 32 bits
527 * and the standard lrand48() routine can be used.
529 if ( max <= (long)2147483647 ) {
530 return (long long) (min + (((long long)lrand48() % nmults) * mult));
533 * max is greater than 2gb - meeds more than 32 bits.
534 * Since lrand48 only will get a number up to 32bits.
536 randnum=divider(min, max, 0, -1);
537 return (long long) (min + ((randnum % nmults) * mult));
543 * This functional will recusively call itself to return a random
544 * number min and max. It was designed to work the 64bit numbers
545 * even when compiled as 32 bit process.
546 * algorithm: to use the official lrand48() routine - limited to 32 bits.
547 * find the difference between min and max (max-min).
548 * if the difference is 2g or less, use the random number gotton from lrand48().
549 * Determine the midway point between min and max.
550 * if the midway point is less than 2g from min or max,
551 * randomly add the random number gotton from lrand48() to
552 * either min or the midpoint.
553 * Otherwise, call outself with min and max being min and midway value or
554 * midway value and max. This will reduce the range in half.
557 divider(long long min, long long max, long long cnt, long long rand)
559 long long med, half, diff;
562 * prevent run away code. We are dividing by two each count.
563 * if we get to a count of more than 32, we should have gotten
570 * Only get a random number the first time.
572 if ( cnt == 0 || rand < -1 ) {
573 rand = (long long)lrand48(); /* 32 bit random number */
578 if ( diff <= 2147483647 )
581 half = diff/(long long)2; /* half the distance between min and max */
582 med = min + half; /* med way point between min and max */
585 printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max, cnt, rand);
586 printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med);
589 if ( half <= 2147483647 ) {
591 * If half is smaller than 2gb, we can use the random number
592 * to pick the number within the min to med or med to max
593 * if the cnt bit of rand is zero or one, respectively.
595 if ( rand & (1<<cnt) )
601 * recursively call ourself to reduce the value to the bottom half
602 * or top half (bit cnt is set).
604 if ( rand & (1<<cnt) ) {
605 return divider(med, max, cnt+1, rand);
607 return divider(min, med, cnt+1, rand);
615 /*****************************************************************************
616 * random_range_seed(s)
618 * Sets the random seed to s. Uses srand48(), assuming that lrand48() will
619 * be used in random_range().
620 *****************************************************************************/
626 extern void srand48();
631 /****************************************************************************
634 * This function randomly returns a single bit from the bits
635 * set in mask. If mask is zero, zero is returned.
637 ****************************************************************************/
639 random_bit(long mask)
641 int nbits = 0; /* number of set bits in mask */
642 long bit; /* used to count bits and num of set bits choosen */
643 int nshift; /* used to count bit shifts */
649 * get the number of bits set in mask
654 for ( nshift=0; nshift<sizeof(long)*8; nshift++) {
665 * randomly choose a bit.
667 bit=random_range(1, nbits, 1, NULL);
670 * shift bits until you determine which bit was randomly choosen.
671 * nshift will hold the number of shifts to make.
676 /* check if the current one's bit is set */
684 return 01L << (nshift-1);
689 #if RANDOM_BIT_UNITTEST
691 * The following is a unit test main function for random_bit().
701 printf("test for first and last bit set\n");
703 ret=random_bit(mask);
704 printf("random_bit(%#o) returned %#o\n", mask, ret);
706 mask=1L<<(sizeof(long)*8-1);
707 ret=random_bit(mask);
708 printf("random_bit(%#o) returned %#o\n", mask, ret);
712 for (ind=2; ind<argc; ind++) {
713 printf("Calling random_bit %d times for mask %#o\n", iter, mask);
714 sscanf(argv[ind], "%i", &mask);
715 for (cnt=0; cnt<iter; cnt++) {
716 ret=random_bit(mask);
717 printf("random_bit(%#o) returned %#o\n", mask, ret);
724 #endif /* end if RANDOM_BIT_UNITTEST */
729 * The following is a unit test main function for random_range*().
732 #define PARTNUM 10 /* used to determine even distribution of random numbers */
733 #define MEG 1024*1024*1024
734 #define GIG 1073741824
742 int imin=0, imult=1, itmin, itmax=0;
744 int imax=6*GIG; /* higher than 32 bits */
749 long lret, lmin=0, lmult=1, ltmin, ltmax=0;
750 #if CRAY || (_MIPS_SZLONG == 64)
751 long lmax=6*(long)GIG; /* higher than 32 bits */
755 long long llret, llmin=0, llmult=1, lltmin, lltmax=0;
756 long long llmax=(long long)80*(long long)GIG;
760 long cntarr[PARTNUM];
761 long valbound[PARTNUM];
762 long long lvalbound[PARTNUM];
764 for (ind=0; ind<PARTNUM; ind++ )
768 printf("Usage: %s func [iterations] \n", argv[0]);
769 printf("func can be random_range, random_rangel, random_rangell\n");
774 if ( sscanf(argv[2], "%i", &iter) != 1 ) {
775 printf("Usage: %s [func iterations] \n", argv[0]);
776 printf("argv[2] is not a number\n");
785 if ( strcmp(argv[1], "random_rangel") == 0 ) {
788 for(ind=0; ind<PARTNUM; ind++) {
789 valbound[ind]=part*ind;
792 for(cnt=0; cnt<iter; cnt++) {
793 lret=random_rangel(lmin, lmax, lmult, NULL);
795 printf("%ld\n", lret);
800 for(ind=0; ind<PARTNUM-1; ind++) {
801 if ( valbound[ind] < lret && lret <= valbound[ind+1] ) {
806 if ( lret > valbound[PARTNUM-1] ) {
810 for(ind=0; ind<PARTNUM-1; ind++) {
811 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1,
812 valbound[ind], valbound[ind+1], cntarr[ind],
813 (float)(cntarr[ind]/(float)iter));
815 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
816 valbound[PARTNUM-1], lmax, cntarr[PARTNUM-1],
817 (float)(cntarr[PARTNUM-1]/(float)iter));
818 printf(" min=%ld, max=%ld\n", ltmin, ltmax);
820 } else if ( strcmp(argv[1], "random_rangell") == 0 ) {
822 * random_rangell() unit test
825 lpart = llmax/PARTNUM;
826 for(ind=0; ind<PARTNUM; ind++) {
827 lvalbound[ind]=(long long)(lpart*ind);
830 for(cnt=0; cnt<iter; cnt++) {
831 llret=random_rangell(llmin, llmax, llmult, NULL);
833 printf("random_rangell returned %lld\n", llret);
834 if ( llret < lltmin )
836 if ( llret > lltmax )
839 for(ind=0; ind<PARTNUM-1; ind++) {
840 if ( lvalbound[ind] < llret && llret <= lvalbound[ind+1] ) {
845 if ( llret > lvalbound[PARTNUM-1] ) {
849 for(ind=0; ind<PARTNUM-1; ind++) {
850 printf("%2d %-13lld to %-13lld %5ld %4.4f\n", ind+1,
851 lvalbound[ind], lvalbound[ind+1], cntarr[ind],
852 (float)(cntarr[ind]/(float)iter));
854 printf("%2d %-13lld to %-13lld %5ld %4.4f\n", PARTNUM,
855 lvalbound[PARTNUM-1], llmax, cntarr[PARTNUM-1],
856 (float)(cntarr[PARTNUM-1]/(float)iter));
857 printf(" min=%lld, max=%lld\n", lltmin, lltmax);
861 * random_range() unit test
865 for(ind=0; ind<PARTNUM; ind++) {
866 valbound[ind]=part*ind;
869 for(cnt=0; cnt<iter; cnt++) {
870 lret=random_range(imin, imax, imult, NULL);
872 printf("%ld\n", lret);
878 for(ind=0; ind<PARTNUM-1; ind++) {
879 if ( valbound[ind] < lret && lret <= valbound[ind+1] ) {
884 if ( lret > valbound[PARTNUM-1] ) {
888 for(ind=0; ind<PARTNUM-1; ind++) {
889 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1,
890 valbound[ind], valbound[ind+1], cntarr[ind],
891 (float)(cntarr[ind]/(float)iter));
893 printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
894 valbound[PARTNUM-1], (long)imax, cntarr[PARTNUM-1],
895 (float)(cntarr[PARTNUM-1]/(float)iter));
896 printf(" min=%d, max=%d\n", itmin, itmax);