Guest User

Untitled

a guest
Jun 7th, 2017
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.77 KB | None | 0 0
  1. static package
  2. bf_random(Var arglist, Byte next, void *vdata, Objid progr)
  3. {
  4. int nargs = arglist.v.list[0].v.num;
  5. int num = (nargs >= 1 ? arglist.v.list[1].v.num : INTNUM_MAX);
  6. Var r;
  7. int e;
  8. int rnd;
  9.  
  10. free_var(arglist);
  11.  
  12. if (num <= 0)
  13. return make_error_pack(E_INVARG);
  14.  
  15. const int range_l =
  16. ((INTNUM_MAX > RAND_MAX ? RAND_MAX : (RAND_MAX - num)) + 1) % num;
  17.  
  18. r.type = TYPE_INT;
  19.  
  20. #if ((RAND_MAX <= 0) || 0!=(RAND_MAX & (RAND_MAX+1)))
  21. # error RAND_MAX+1 is not a positive power of 2 ??
  22. #endif
  23.  
  24. #if (INTNUM_MAX > RAND_MAX)
  25. /* num >= RAND_MAX possible; launch general algorithm */
  26.  
  27. # define RANGE (RAND_MAX+1)
  28. # define OR_ZERO(n) (n)
  29.  
  30. rnd = 0;
  31. e = 1;
  32. #else
  33. /* num >= RAND_MAX not possible; unroll first loop iteration */
  34.  
  35. # define OR_ZERO(n) 0
  36.  
  37. rnd = RANDOM();
  38. e = range_l;
  39.  
  40. if (rnd >= e) {
  41. r.v.num = 1 + rnd % num;
  42. return make_var_pack(r);
  43. }
  44. #endif
  45.  
  46. for (;;) {
  47. /* INVARIANT: rnd uniform over [0..e-1] */
  48. int rnd_next = RANDOM();
  49.  
  50. #if RAND_MAX < INTNUM_MAX
  51. /* compiler should turn [/%*]RANGE into bitwise ops */
  52. while (e < (num/RANGE) ||
  53. ((e == num/RANGE) && (num%RANGE != 0))) {
  54. rnd = rnd*RANGE + rnd_next;
  55. e *= RANGE;
  56. rnd_next = RANDOM();
  57. }
  58. #endif
  59. /* INVARIANTS:
  60. * e*RANGE >= num
  61. * rnd uniform over [0..e-1]
  62. * rnd*RANGE + rnd_next uniform over [0..e*RANGE-1]
  63. */
  64. if (rnd > OR_ZERO(num/RANGE)) {
  65. /* rnd*RANGE > num */
  66. r.v.num = 1 + muladdmod(rnd, range_l, rnd_next, num);
  67. break;
  68. }
  69. rnd = OR_ZERO(rnd*RANGE) + rnd_next;
  70. e = muladdmod(e, range_l, 0, num);
  71.  
  72. if (rnd >= e) {
  73. r.v.num = 1 + rnd % num;
  74. break;
  75. }
  76. }
  77. return make_var_pack(r);
  78. #undef RANGE
  79. #undef OR_ZERO
  80. }
Advertisement
Add Comment
Please, Sign In to add comment