whr | b973f2b | 2000-05-05 19:34:50 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. |
| 3 | * |
| 4 | * 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. |
| 7 | * |
| 8 | * 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. |
| 11 | * |
| 12 | * 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. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License along |
| 20 | * with this program; if not, write the Free Software Foundation, Inc., 59 |
| 21 | * Temple Place - Suite 330, Boston MA 02111-1307, USA. |
| 22 | * |
| 23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, |
| 24 | * Mountain View, CA 94043, or: |
| 25 | * |
| 26 | * http://www.sgi.com |
| 27 | * |
| 28 | * For further information regarding this notice, see: |
| 29 | * |
| 30 | * 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 | |
| 42 | struct range { |
| 43 | int min; |
| 44 | int max; |
| 45 | int mult; |
| 46 | }; |
| 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 |
| 72 | * defmax default value to plug in for max, if it is missing |
| 73 | * 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 |
| 80 | * into an integer, or >= 0 if it was successfully |
| 81 | * 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 | |
| 98 | static int str_to_int(); |
| 99 | static long long divider(long long, long long, long long, long long); |
| 100 | |
| 101 | int |
| 102 | parse_ranges(str, defmin, defmax, defmult, parse_func, rangeptr, errptr) |
| 103 | char *str; |
| 104 | int defmin; |
| 105 | int defmax; |
| 106 | int defmult; |
| 107 | int (*parse_func)(); |
| 108 | char **rangeptr; |
| 109 | char **errptr; |
| 110 | { |
| 111 | int ncommas; |
| 112 | char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr; |
| 113 | struct range *rp, *ranges; |
| 114 | static char errmsg[256]; |
| 115 | |
| 116 | if (errptr != NULL) { |
| 117 | *errptr = errmsg; |
| 118 | } |
| 119 | |
| 120 | for (ncommas = 0, cp = str; *cp != '\0'; cp++) { |
| 121 | if (*cp == ',') { |
| 122 | ncommas++; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | if (parse_func == NULL) { |
| 127 | parse_func = str_to_int; |
| 128 | } |
| 129 | |
| 130 | tmpstr = strdup(str); |
| 131 | ranges = (struct range *)malloc((ncommas+1) * sizeof(struct range)); |
| 132 | rp = ranges; |
| 133 | |
| 134 | tok = strtok(tmpstr, ","); |
| 135 | while (tok != NULL) { |
| 136 | n1str = tok; |
| 137 | n2str = NULL; |
| 138 | multstr = NULL; |
| 139 | |
| 140 | rp->min = defmin; |
| 141 | rp->max = defmax; |
| 142 | rp->mult = defmult; |
| 143 | |
| 144 | if ((cp = strchr(n1str, ':')) != NULL) { |
| 145 | *cp = '\0'; |
| 146 | n2str = cp+1; |
| 147 | |
| 148 | if ((cp = strchr(n2str, ':')) != NULL) { |
| 149 | *cp = '\0'; |
| 150 | multstr = cp+1; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | * Parse the 'min' field - if it is zero length (:n2[:mult] |
| 156 | * format), retain the default value, otherwise, pass the |
| 157 | * string to the parse function. |
| 158 | */ |
| 159 | |
| 160 | if ((int)strlen(n1str) > 0) { |
| 161 | if ((*parse_func)(n1str, &rp->min) < 0) { |
| 162 | sprintf(errmsg, "error parsing string %s into an integer", n1str); |
| 163 | free(tmpstr); |
| 164 | free(ranges); |
| 165 | return -1; |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | /* |
| 170 | * Process the 'max' field - if one was not present (n1 format) |
| 171 | * set max equal to min. If the field was present, but |
| 172 | * zero length (n1: format), retain the default. Otherwise |
| 173 | * pass the string to the parse function. |
| 174 | */ |
| 175 | |
| 176 | if (n2str == NULL) { |
| 177 | rp->max = rp->min; |
| 178 | } else if ((int)strlen(n2str) > 0) { |
| 179 | if ((*parse_func)(n2str, &rp->max) < 0) { |
| 180 | sprintf(errmsg, "error parsing string %s into an integer", n2str); |
| 181 | free(tmpstr); |
| 182 | free(ranges); |
| 183 | return -1; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * Process the 'mult' field - if one was not present |
| 189 | * (n1:n2 format), or the field was zero length (n1:n2: format) |
| 190 | * then set the mult field to defmult - otherwise pass then |
| 191 | * mult field to the parse function. |
| 192 | */ |
| 193 | |
| 194 | if (multstr != NULL && (int)strlen(multstr) > 0) { |
| 195 | if ((*parse_func)(multstr, &rp->mult) < 0) { |
| 196 | sprintf(errmsg, "error parsing string %s into an integer", multstr); |
| 197 | free(tmpstr); |
| 198 | free(ranges); |
| 199 | return -1; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | rp++; |
| 204 | tok = strtok(NULL, ","); |
| 205 | } |
| 206 | |
| 207 | free(tmpstr); |
| 208 | |
| 209 | if (rangeptr != NULL) { |
| 210 | *rangeptr = (char *)ranges; |
| 211 | } else { |
| 212 | free(ranges); /* just running in parse mode */ |
| 213 | } |
| 214 | |
| 215 | return (rp - ranges); |
| 216 | } |
| 217 | |
| 218 | /* |
| 219 | * The default integer-parsing function |
| 220 | */ |
| 221 | |
| 222 | static int |
| 223 | str_to_int(str, ip) |
| 224 | char *str; |
| 225 | int *ip; |
| 226 | { |
| 227 | char c; |
| 228 | |
| 229 | if (sscanf(str, "%i%c", ip, &c) != 1) { |
| 230 | return -1; |
| 231 | } else { |
| 232 | return 0; |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | * Three simple functions to return the min, max, and mult values for a given |
| 238 | * range. It is assumed that rbuf is a range buffer set up by parse_ranges(), |
| 239 | * and that r is a valid range within that buffer. |
| 240 | */ |
| 241 | |
| 242 | int |
| 243 | range_min(rbuf, r) |
| 244 | char *rbuf; |
| 245 | int r; |
| 246 | { |
| 247 | return ((struct range *)rbuf)[r].min; |
| 248 | } |
| 249 | |
| 250 | int |
| 251 | range_max(rbuf, r) |
| 252 | char *rbuf; |
| 253 | int r; |
| 254 | { |
| 255 | return ((struct range *)rbuf)[r].max; |
| 256 | } |
| 257 | |
| 258 | int |
| 259 | range_mult(rbuf, r) |
| 260 | char *rbuf; |
| 261 | int r; |
| 262 | { |
| 263 | return ((struct range *)rbuf)[r].mult; |
| 264 | } |
| 265 | |
| 266 | /***************************************************************************** |
| 267 | * random_range(int start, int end, int mult, char **errp) |
| 268 | * |
| 269 | * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple |
| 270 | * of 'mult'. Start and end may be any valid integer, but mult must be an |
| 271 | * integer > 0. errp is a char ** which will be set to point to a static |
| 272 | * error message buffer if it is not NULL, and an error occurs. |
| 273 | * |
| 274 | * The errp is the only way to check if the routine fails - currently the only |
| 275 | * failure conditions are: |
| 276 | * |
| 277 | * mult < 1 |
| 278 | * no numbers in the start-end range that are a multiple of 'mult' |
| 279 | * |
| 280 | * If random_range_fails, and errp is a valid pointer, it will point to an |
| 281 | * internal error buffer. If errp is a vaild pointer, and random_range |
| 282 | * is successful, errp will be set to NULL. |
| 283 | * |
| 284 | * Note - if mult is 1 (the most common case), there are error conditions |
| 285 | * possible, and errp need not be used. |
| 286 | * |
| 287 | * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when |
| 288 | * setting the seed. |
| 289 | *****************************************************************************/ |
| 290 | |
| 291 | long |
| 292 | random_range(min, max, mult, errp) |
| 293 | int min; |
| 294 | int max; |
| 295 | int mult; |
| 296 | char **errp; |
| 297 | { |
| 298 | int r, nmults, orig_min, orig_max, orig_mult, tmp; |
| 299 | extern long lrand48(); |
| 300 | static char errbuf[128]; |
| 301 | |
| 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 | |
| 336 | if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ |
| 337 | min += mult - r; |
| 338 | |
| 339 | if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ |
| 340 | max -= r; |
| 341 | |
| 342 | if (min > max) { /* no 'mult' multiples between min & max */ |
| 343 | if (errp != NULL) { |
| 344 | sprintf(errbuf, "no numbers in the range %d:%d that are a multiple of %d", orig_min, orig_max, orig_mult); |
| 345 | *errp = errbuf; |
| 346 | } |
| 347 | return -1; |
| 348 | } |
| 349 | |
| 350 | if (errp != NULL) { |
| 351 | *errp = NULL; |
| 352 | } |
| 353 | |
| 354 | nmults = ((max - min) / mult) + 1; |
| 355 | #if CRAY |
| 356 | /* |
| 357 | * If max is less than 2gb, then the value can fit in 32 bits |
| 358 | * and the standard lrand48() routine can be used. |
| 359 | */ |
| 360 | if ( max <= (long)2147483647 ) { |
| 361 | return (long) (min + (((long)lrand48() % nmults) * mult)); |
| 362 | } else { |
| 363 | /* |
| 364 | * max is greater than 2gb - meeds more than 32 bits. |
| 365 | * Since lrand48 only will get a number up to 32bits. |
| 366 | */ |
| 367 | long randnum; |
| 368 | randnum=divider(min, max, 0, -1); |
| 369 | return (long) (min + ((randnum % nmults) * mult)); |
| 370 | } |
| 371 | |
| 372 | #else |
| 373 | return (min + ((lrand48() % nmults) * mult)); |
| 374 | #endif |
| 375 | |
| 376 | } |
| 377 | |
| 378 | /* |
| 379 | * Just like random_range, but all values are longs. |
| 380 | */ |
| 381 | long |
| 382 | random_rangel(min, max, mult, errp) |
| 383 | long min; |
| 384 | long max; |
| 385 | long mult; |
| 386 | char **errp; |
| 387 | { |
| 388 | long r, nmults, orig_min, orig_max, orig_mult, tmp; |
| 389 | extern long lrand48(); |
| 390 | static char errbuf[128]; |
| 391 | |
| 392 | /* |
| 393 | * Sanity check |
| 394 | */ |
| 395 | |
| 396 | if (mult < 1) { |
| 397 | if (errp != NULL) { |
| 398 | sprintf(errbuf, "mult arg must be greater than 0"); |
| 399 | *errp = errbuf; |
| 400 | } |
| 401 | return -1; |
| 402 | } |
| 403 | |
| 404 | /* |
| 405 | * Save original parameter values for use in error message |
| 406 | */ |
| 407 | |
| 408 | orig_min = min; |
| 409 | orig_max = max; |
| 410 | orig_mult = mult; |
| 411 | |
| 412 | /* |
| 413 | * switch min/max if max < min |
| 414 | */ |
| 415 | |
| 416 | if (max < min) { |
| 417 | tmp = max; |
| 418 | max = min; |
| 419 | min = tmp; |
| 420 | } |
| 421 | |
| 422 | /* |
| 423 | * select the random number |
| 424 | */ |
| 425 | |
| 426 | if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ |
| 427 | min += mult - r; |
| 428 | |
| 429 | if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ |
| 430 | max -= r; |
| 431 | |
| 432 | if (min > max) { /* no 'mult' multiples between min & max */ |
| 433 | if (errp != NULL) { |
| 434 | sprintf(errbuf, |
| 435 | "no numbers in the range %ld:%ld that are a multiple of %ld", |
| 436 | orig_min, orig_max, orig_mult); |
| 437 | *errp = errbuf; |
| 438 | } |
| 439 | return -1; |
| 440 | } |
| 441 | |
| 442 | if (errp != NULL) { |
| 443 | *errp = NULL; |
| 444 | } |
| 445 | |
| 446 | nmults = ((max - min) / mult) + 1; |
| 447 | #if CRAY || (_MIPS_SZLONG == 64) |
| 448 | /* |
| 449 | * If max is less than 2gb, then the value can fit in 32 bits |
| 450 | * and the standard lrand48() routine can be used. |
| 451 | */ |
| 452 | if ( max <= (long)2147483647 ) { |
| 453 | return (long) (min + (((long)lrand48() % nmults) * mult)); |
| 454 | } else { |
| 455 | /* |
| 456 | * max is greater than 2gb - meeds more than 32 bits. |
| 457 | * Since lrand48 only will get a number up to 32bits. |
| 458 | */ |
| 459 | long randnum; |
| 460 | randnum=divider(min, max, 0, -1); |
| 461 | return (long) (min + ((randnum % nmults) * mult)); |
| 462 | } |
| 463 | |
| 464 | #else |
| 465 | return (min + ((lrand48() % nmults) * mult)); |
| 466 | #endif |
| 467 | } |
| 468 | |
| 469 | /* |
| 470 | * Attempts to be just like random_range, but everything is long long (64 bit) |
| 471 | */ |
| 472 | long long |
| 473 | random_rangell(min, max, mult, errp) |
| 474 | long long min; |
| 475 | long long max; |
| 476 | long long mult; |
| 477 | char **errp; |
| 478 | { |
| 479 | long long r, nmults, orig_min, orig_max, orig_mult, tmp; |
| 480 | long long randnum; |
| 481 | extern long lrand48(); |
| 482 | static char errbuf[128]; |
| 483 | |
| 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 | |
| 518 | if ((r = min % mult)) /* bump to the next higher 'mult' multiple */ |
| 519 | min += mult - r; |
| 520 | |
| 521 | if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */ |
| 522 | max -= r; |
| 523 | |
| 524 | if (min > max) { /* no 'mult' multiples between min & max */ |
| 525 | if (errp != NULL) { |
| 526 | 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; |
| 530 | } |
| 531 | return -1; |
| 532 | } |
| 533 | |
| 534 | if (errp != NULL) { |
| 535 | *errp = NULL; |
| 536 | } |
| 537 | |
| 538 | nmults = ((max - min) / mult) + 1; |
| 539 | /* |
| 540 | * If max is less than 2gb, then the value can fit in 32 bits |
| 541 | * and the standard lrand48() routine can be used. |
| 542 | */ |
| 543 | if ( max <= (long)2147483647 ) { |
| 544 | return (long long) (min + (((long long)lrand48() % nmults) * mult)); |
| 545 | } else { |
| 546 | /* |
| 547 | * max is greater than 2gb - meeds more than 32 bits. |
| 548 | * Since lrand48 only will get a number up to 32bits. |
| 549 | */ |
| 550 | randnum=divider(min, max, 0, -1); |
| 551 | return (long long) (min + ((randnum % nmults) * mult)); |
| 552 | } |
| 553 | |
| 554 | } |
| 555 | |
| 556 | /* |
| 557 | * This functional will recusively call itself to return a random |
| 558 | * number min and max. It was designed to work the 64bit numbers |
| 559 | * even when compiled as 32 bit process. |
| 560 | * algorithm: to use the official lrand48() routine - limited to 32 bits. |
| 561 | * find the difference between min and max (max-min). |
| 562 | * if the difference is 2g or less, use the random number gotton from lrand48(). |
| 563 | * Determine the midway point between min and max. |
| 564 | * if the midway point is less than 2g from min or max, |
| 565 | * randomly add the random number gotton from lrand48() to |
| 566 | * either min or the midpoint. |
| 567 | * Otherwise, call outself with min and max being min and midway value or |
| 568 | * midway value and max. This will reduce the range in half. |
| 569 | */ |
| 570 | static long long |
| 571 | divider(long long min, long long max, long long cnt, long long rand) |
| 572 | { |
| 573 | long long med, half, diff; |
| 574 | |
| 575 | /* |
| 576 | * prevent run away code. We are dividing by two each count. |
| 577 | * if we get to a count of more than 32, we should have gotten |
| 578 | * to 2gb. |
| 579 | */ |
| 580 | if ( cnt > 32 ) |
| 581 | return -1; |
| 582 | |
| 583 | /* |
| 584 | * Only get a random number the first time. |
| 585 | */ |
| 586 | if ( cnt == 0 || rand < -1 ) { |
| 587 | rand = (long long)lrand48(); /* 32 bit random number */ |
| 588 | } |
| 589 | |
| 590 | diff = max - min; |
| 591 | |
| 592 | if ( diff <= 2147483647 ) |
| 593 | return min + rand; |
| 594 | |
| 595 | half = diff/(long long)2; /* half the distance between min and max */ |
| 596 | med = min + half; /* med way point between min and max */ |
| 597 | |
| 598 | #if DEBUG |
| 599 | printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max, cnt, rand); |
| 600 | printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med); |
| 601 | #endif |
| 602 | |
| 603 | if ( half <= 2147483647 ) { |
| 604 | /* |
| 605 | * If half is smaller than 2gb, we can use the random number |
| 606 | * to pick the number within the min to med or med to max |
| 607 | * if the cnt bit of rand is zero or one, respectively. |
| 608 | */ |
| 609 | if ( rand & (1<<cnt) ) |
| 610 | return med + rand; |
| 611 | else |
| 612 | return min + rand; |
| 613 | } else { |
| 614 | /* |
| 615 | * recursively call ourself to reduce the value to the bottom half |
| 616 | * or top half (bit cnt is set). |
| 617 | */ |
| 618 | if ( rand & (1<<cnt) ) { |
| 619 | return divider(med, max, cnt+1, rand); |
| 620 | } else { |
| 621 | return divider(min, med, cnt+1, rand); |
| 622 | } |
| 623 | |
| 624 | } |
| 625 | |
| 626 | } |
| 627 | |
| 628 | |
| 629 | /***************************************************************************** |
| 630 | * random_range_seed(s) |
| 631 | * |
| 632 | * Sets the random seed to s. Uses srand48(), assuming that lrand48() will |
| 633 | * be used in random_range(). |
| 634 | *****************************************************************************/ |
| 635 | |
| 636 | void |
| 637 | random_range_seed(s) |
| 638 | long s; |
| 639 | { |
| 640 | extern void srand48(); |
| 641 | |
| 642 | srand48(s); |
| 643 | } |
| 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 | ****************************************************************************/ |
| 652 | long |
| 653 | random_bit(long mask) |
| 654 | { |
| 655 | int nbits = 0; /* number of set bits in mask */ |
| 656 | long bit; /* used to count bits and num of set bits choosen */ |
| 657 | int nshift; /* used to count bit shifts */ |
| 658 | |
| 659 | if ( mask == 0 ) |
| 660 | return 0; |
| 661 | |
| 662 | /* |
| 663 | * get the number of bits set in mask |
| 664 | */ |
| 665 | #ifndef CRAY |
| 666 | |
| 667 | bit=1L; |
robbiew | 0ccc827 | 2003-06-18 17:44:03 +0000 | [diff] [blame] | 668 | for ( nshift=0; (unsigned int)nshift<sizeof(long)*8; nshift++) { |
whr | b973f2b | 2000-05-05 19:34:50 +0000 | [diff] [blame] | 669 | if ( mask & bit ) |
| 670 | nbits++; |
| 671 | bit=bit<<1; |
| 672 | } |
| 673 | |
| 674 | #else |
| 675 | nbits=_popcnt(mask); |
| 676 | #endif /* if CRAY */ |
| 677 | |
| 678 | /* |
| 679 | * randomly choose a bit. |
| 680 | */ |
| 681 | bit=random_range(1, nbits, 1, NULL); |
| 682 | |
| 683 | /* |
| 684 | * shift bits until you determine which bit was randomly choosen. |
| 685 | * nshift will hold the number of shifts to make. |
| 686 | */ |
| 687 | |
| 688 | nshift=0; |
| 689 | while (bit) { |
| 690 | /* check if the current one's bit is set */ |
| 691 | if ( mask & 1L ) { |
| 692 | bit--; |
| 693 | } |
| 694 | mask = mask >> 1; |
| 695 | nshift++; |
| 696 | } |
| 697 | |
| 698 | return 01L << (nshift-1); |
| 699 | |
| 700 | } |
| 701 | |
| 702 | |
| 703 | #if RANDOM_BIT_UNITTEST |
| 704 | /* |
| 705 | * The following is a unit test main function for random_bit(). |
| 706 | */ |
| 707 | main(argc, argv) |
| 708 | int argc; |
| 709 | char **argv; |
| 710 | { |
| 711 | int ind; |
| 712 | int cnt, iter; |
| 713 | long mask, ret; |
| 714 | |
| 715 | printf("test for first and last bit set\n"); |
| 716 | mask=1L; |
| 717 | ret=random_bit(mask); |
| 718 | printf("random_bit(%#o) returned %#o\n", mask, ret); |
| 719 | |
| 720 | mask=1L<<(sizeof(long)*8-1); |
| 721 | ret=random_bit(mask); |
| 722 | printf("random_bit(%#o) returned %#o\n", mask, ret); |
| 723 | |
| 724 | if ( argc >= 3 ) { |
| 725 | iter=atoi(argv[1]); |
| 726 | for (ind=2; ind<argc; ind++) { |
| 727 | printf("Calling random_bit %d times for mask %#o\n", iter, mask); |
| 728 | sscanf(argv[ind], "%i", &mask); |
| 729 | for (cnt=0; cnt<iter; cnt++) { |
| 730 | ret=random_bit(mask); |
| 731 | printf("random_bit(%#o) returned %#o\n", mask, ret); |
| 732 | } |
| 733 | } |
| 734 | } |
| 735 | exit(0); |
| 736 | } |
| 737 | |
| 738 | #endif /* end if RANDOM_BIT_UNITTEST */ |
| 739 | |
| 740 | |
| 741 | #if UNIT_TEST |
| 742 | /* |
| 743 | * The following is a unit test main function for random_range*(). |
| 744 | */ |
| 745 | |
| 746 | #define PARTNUM 10 /* used to determine even distribution of random numbers */ |
| 747 | #define MEG 1024*1024*1024 |
| 748 | #define GIG 1073741824 |
| 749 | int |
| 750 | main(argc, argv) |
| 751 | int argc; |
| 752 | char **argv; |
| 753 | { |
| 754 | int ind; |
| 755 | int cnt, iter=10; |
| 756 | int imin=0, imult=1, itmin, itmax=0; |
| 757 | #if CRAY |
| 758 | int imax=6*GIG; /* higher than 32 bits */ |
| 759 | #else |
| 760 | int imax=1048576; |
| 761 | #endif |
| 762 | |
| 763 | long lret, lmin=0, lmult=1, ltmin, ltmax=0; |
| 764 | #if CRAY || (_MIPS_SZLONG == 64) |
| 765 | long lmax=6*(long)GIG; /* higher than 32 bits */ |
| 766 | #else |
| 767 | long lmax=1048576; |
| 768 | #endif |
| 769 | long long llret, llmin=0, llmult=1, lltmin, lltmax=0; |
| 770 | long long llmax=(long long)80*(long long)GIG; |
| 771 | |
| 772 | long part; |
| 773 | long long lpart; |
| 774 | long cntarr[PARTNUM]; |
| 775 | long valbound[PARTNUM]; |
| 776 | long long lvalbound[PARTNUM]; |
| 777 | |
| 778 | for (ind=0; ind<PARTNUM; ind++ ) |
| 779 | cntarr[ind]=0; |
| 780 | |
| 781 | if ( argc < 2 ) { |
| 782 | printf("Usage: %s func [iterations] \n", argv[0]); |
| 783 | printf("func can be random_range, random_rangel, random_rangell\n"); |
| 784 | exit(1); |
| 785 | } |
| 786 | |
| 787 | if ( argc >= 3 ) { |
| 788 | if ( sscanf(argv[2], "%i", &iter) != 1 ) { |
| 789 | printf("Usage: %s [func iterations] \n", argv[0]); |
| 790 | printf("argv[2] is not a number\n"); |
| 791 | exit(1); |
| 792 | } |
| 793 | } |
| 794 | |
| 795 | |
| 796 | /* |
| 797 | * random_rangel () |
| 798 | */ |
| 799 | if ( strcmp(argv[1], "random_rangel") == 0 ) { |
| 800 | ltmin=lmax; |
| 801 | part = lmax/PARTNUM; |
| 802 | for(ind=0; ind<PARTNUM; ind++) { |
| 803 | valbound[ind]=part*ind; |
| 804 | } |
| 805 | |
| 806 | for(cnt=0; cnt<iter; cnt++) { |
| 807 | lret=random_rangel(lmin, lmax, lmult, NULL); |
| 808 | if ( iter < 100 ) |
| 809 | printf("%ld\n", lret); |
| 810 | if ( lret < ltmin ) |
| 811 | ltmin = lret; |
| 812 | if ( lret > ltmax ) |
| 813 | ltmax = lret; |
| 814 | for(ind=0; ind<PARTNUM-1; ind++) { |
| 815 | if ( valbound[ind] < lret && lret <= valbound[ind+1] ) { |
| 816 | cntarr[ind]++; |
| 817 | break; |
| 818 | } |
| 819 | } |
| 820 | if ( lret > valbound[PARTNUM-1] ) { |
| 821 | cntarr[PARTNUM-1]++; |
| 822 | } |
| 823 | } |
| 824 | for(ind=0; ind<PARTNUM-1; ind++) { |
| 825 | printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1, |
| 826 | valbound[ind], valbound[ind+1], cntarr[ind], |
| 827 | (float)(cntarr[ind]/(float)iter)); |
| 828 | } |
| 829 | printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM, |
| 830 | valbound[PARTNUM-1], lmax, cntarr[PARTNUM-1], |
| 831 | (float)(cntarr[PARTNUM-1]/(float)iter)); |
| 832 | printf(" min=%ld, max=%ld\n", ltmin, ltmax); |
| 833 | |
| 834 | } else if ( strcmp(argv[1], "random_rangell") == 0 ) { |
| 835 | /* |
| 836 | * random_rangell() unit test |
| 837 | */ |
| 838 | lltmin=llmax; |
| 839 | lpart = llmax/PARTNUM; |
| 840 | for(ind=0; ind<PARTNUM; ind++) { |
| 841 | lvalbound[ind]=(long long)(lpart*ind); |
| 842 | } |
| 843 | |
| 844 | for(cnt=0; cnt<iter; cnt++) { |
| 845 | llret=random_rangell(llmin, llmax, llmult, NULL); |
| 846 | if ( iter < 100 ) |
| 847 | printf("random_rangell returned %lld\n", llret); |
| 848 | if ( llret < lltmin ) |
| 849 | lltmin = llret; |
| 850 | if ( llret > lltmax ) |
| 851 | lltmax = llret; |
| 852 | |
| 853 | for(ind=0; ind<PARTNUM-1; ind++) { |
| 854 | if ( lvalbound[ind] < llret && 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", ind+1, |
| 865 | lvalbound[ind], lvalbound[ind+1], cntarr[ind], |
| 866 | (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 && lret <= valbound[ind+1] ) { |
| 894 | cntarr[ind]++; |
| 895 | break; |
| 896 | } |
| 897 | } |
| 898 | if ( lret > valbound[PARTNUM-1] ) { |
| 899 | cntarr[PARTNUM-1]++; |
| 900 | } |
| 901 | } |
| 902 | for(ind=0; ind<PARTNUM-1; ind++) { |
| 903 | printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1, |
| 904 | valbound[ind], valbound[ind+1], cntarr[ind], |
| 905 | (float)(cntarr[ind]/(float)iter)); |
| 906 | } |
| 907 | printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM, |
| 908 | valbound[PARTNUM-1], (long)imax, cntarr[PARTNUM-1], |
| 909 | (float)(cntarr[PARTNUM-1]/(float)iter)); |
| 910 | printf(" min=%d, max=%d\n", itmin, itmax); |
| 911 | |
| 912 | } |
| 913 | |
| 914 | exit(0); |
| 915 | } |
| 916 | |
| 917 | #endif |