Snippets
  • Uploaded By: maroon
  • Added: 2 years ago
  • Updated: Never
  • mIRC Version: 6.35 & up
  • Hits: 815
  • Size: 9.75KB
  • Downloads: 3
  • Review By: entropy



randfix v1.0

substitute for $rand
eliminates modulo and minimizes swiss cheese bias bugs in $rand through v7.54
allows negative numbers in the range
allows much larger range of random numbers
includes alias to calculate standard deviation for series of numbers
Screenshot...

  
  1    0  Login to Vote.


Source Code:
  1. /*
  2. { $randfix( N1,N2 | char1,char2 ) by maroon v1.0
  3.  
  4. Can be pasted into any existing script
  5. If using the optional :START: and :CONNECT: initialization, these can safely be
  6. inserted inside existing event handlers
  7.  
  8. same syntax as $rand except:
  9. 1. is 'more random' (at least through v7.54)
  10. 2. increases range from 46.5bits (14 9's) to 53bits
  11. 3. permits N1 or both N1/N2 being negative
  12. 4. valid range is N1 >= -2^53, N2 and range size as high as 2^53-1
  13. 5. smooths out modulo and granularity bias in $rand
  14.  
  15. Incompatibilities:
  16. 1. Doesn't support using numeric portion of non-numeric parameters.
  17. $rand(1x,99x) returns random number from 1-99. $randfix(1x,99x) returns random
  18. codepoint from $asc(1) through $asc(9).
  19. 2. Negative numbers are now valid numeric parameters. $rand(-5,5) returns null, while
  20. $randfix returns random number from that range. $rand(-1,-10) always returns a hyphen
  21. while $randfix returns random number from that range.
  22.  
  23. This is a work-around to address the $rand bugs reported here: https://forums.mirc.com/ubbthreads.php/topics/264732/$rand_bias#Post264732
  24. The $rand identifier produces an uneven distribution at largest ranges, and at least
  25. as low as 2^24 range has swiss-cheese holes in the frequency distribution, having
  26. output numbers which are either too-rare, too-common, or impossible. These holes
  27. become larger as the range size increases.
  28.  
  29. This alias offers 3 methods of creating a 53bit value used as input to the rand function.
  30.  
  31. To avoid the swiss-cheese granularity issue, Methods #1 and #2 simulate a 53bit number by
  32. joining several $rand() outputs together. Assuming there are not impossible combinations of
  33. consecutive outputs from small $rand ranges, assembling them into a 53bit number should
  34. make all 53-bit numbers possible from $randfix(0,$calc(2^53-1)). Method#2 performs an XOR
  35. of each 53bit number against the prior 53bit number, ensuring that all 53bit numbers are
  36. possible. Method#3 collects entropy with each use, then stores it in a sha512 hash, avoiding
  37. the impossibity of consecutive 53bit values.
  38.  
  39. To avoid adding a modulo bias, $randfix discards a portion of the 53-bit number range which
  40. would be extra inputs not available to all outputs, continuing to fetch 53-bit numbers until
  41. obtaining a qualifying number. There is a commented scriptline offering an optional $3
  42. parameter which lets you force the 1st 53bit number to be a specific value. You can use this
  43. parameter to test that $randfix is correctly identifying the range of 53bit numbers which
  44. should be discarded. (By whether the output is fixed or random)
  45.  
  46. The default $get_53bit_rand identifier is the fastest of several choices offered.
  47. You can edit this alias to use a different type of $get_53bit_rand alias, or make extra
  48. copies of this alias each using different 'get' aliases for different tasks.
  49.  
  50. Random character from printable ASCII range:
  51. //echo -a $randfix(!,~)
  52. Random RGB color:
  53. //echo -a $rgb($randfix(0,$calc(2^24-1)))
  54. }
  55. */
  56.  
  57. on *:START:.timer -om 10 $randfix(999,9999) noop Initializing $ $+ randfix(1,9)
  58. on *:CONNECT:.timer -om 10 $randfix(999,9999) noop Initializing $ $+ randfix(1,9)
  59.  
  60. alias randfix {
  61. if (($1 == $null) || ($2 == $null)) goto syntax
  62. if (($1 !isnum) || ($2 !isnum)) var %lo $asc($1) , %hi $asc($2) , %num 0
  63. else var %lo $int($1) , %hi $int($2) , %num 1
  64. if (%lo > %hi) var %lo $v2 , %hi $v1
  65. var %diff %hi - %lo , %out_range %diff + 1 , %max.val 9007199254740991
  66. if ((%hi > %max.val) || (%diff > %max.val) || (%lo < -9007199254740992)) goto syntax
  67.  
  68. var %throwaway_above $calc(%max.val - (((%max.val % %out_range) + 1) % %out_range) )
  69.  
  70. var %int53 $get_53bit_rand
  71. ;if ($3 isnum) var -s %int53 $int($3) | else var %int53 $get_53bit_rand
  72. while (%int53 > %throwaway_above) { var %int53 $get_53bit_rand }
  73.  
  74. if (%num) return $calc(%lo + %int53 % %out_range)
  75. return $chr($calc(%lo + %int53 % %out_range))
  76. :syntax
  77. echo -sc info2 *$randfix( N1,N2 |char1,char2) by maroon $+ $chr(169) MinN1:-2^53 MaxN2/range.max:+2^53-1
  78. halt
  79. }
  80.  
  81. ; These 3 are alternate methods of generating 53-bit random numbers.
  82. ; #1 assumes the modulo and frequency distribution bias are negligible at 12bit range or less
  83. ; #2 calculates 53-bit random value same way as #1, but returns the XOR of the current
  84. ; random value against those from the prior random call.
  85. ; #3 uses sha512 string taking entropy from $rand and several other identifiers
  86. ; it also uses the prior random call's sha512 digest, adding entropy with each call
  87.  
  88. alias get_53bit_rand {
  89. return $calc($r(0,255) + $r(0,2047) * 256 + $r(0,2047) * 524288 + $r(0,2047) * 1073741824 + $r(0,4095) * 2199023255552)
  90. } ; 53bit value from joining bit sizes 12:11:11:11:8
  91. ; Note that all the above random inputs affect the calculation when the range size
  92. ; is NOT a factor of 256, i.e. ranges 0-1, 1-8, 0-127
  93.  
  94. alias get_53bit_rand-2 {
  95. var %a $xor(0 $+ $hget(randfix,a),$calc($r(0,255) + $r(0,2047) * 256 + $r(0,2047) * 524288))
  96. var %b $xor(0 $+ $hget(randfix,b),$calc($r(0,2047) + $r(0,4095) * 2048))
  97. hadd -m1 randfix a %a | hadd randfix b %b
  98. return $calc(%a + %b * 1073741824)
  99. } ; XOR's 53bit value against prior 53bit value. Must use separate XOR's due to
  100. ; $xor's 32-bit limitation. a=30bits 11:11:8 b=23bits 12:11
  101.  
  102. alias get_53bit_rand-3 {
  103. var %nonce 0 $+ $hget(randfix,nonce) + 1
  104. var %a $sha512(%nonce $r(0,99999999999999) $ticks $eventid $active $ctime $ial(*,$r(1,$ial(*,0))) $hget(randfix,sha512))
  105. hadd -m1 randfix nonce %nonce | hadd randfix sha512 %a
  106. var %offset $calc(1+$base($right(%a,1),16,10) * 7)
  107. var %r2 4503599627370496 | if ($mid(%a,127,1) isnum 0-7) var %r2 0
  108. var %r1 $base($mid(%a,%offset,13),16,10) + %r2
  109. return %r1
  110. } ; XOR's 53bit value against prior 53bit value. Must use separate XOR's due to
  111. ; $xor's 32-bit limitation. a=30bits 11:11:8 b=23bits 12:11
  112. ; final nibble of digest used to decide which 12 hex digits are used as 52 bits
  113. ; the next-to-last nibble is the 13th bit
  114.  
  115. ; An optional way to gather entropy for Method#3's sha512 value is to hash all the text
  116. ; logfiles for all open channels on the current network:
  117. ; alias randfixentropy var %i $chan(0) , %a $hget(randfix,sha512) | while (%i) { if ($chan(%i).logfile) var %a %a $sha512($v1,2) | dec %i } | hadd -m1 randfix sha512 $sha512($ticks %a)
  118.  
  119. ; randbiasdemo v1.1 by maroon. Demonstrates the modulo bias in $rand through v7.54
  120. ; Due to the task requiring several hours, this does not test for the granularity issue where
  121. ; many values in ranges as small as 24bits are either rare or impossible.
  122. ; At default .996, the 1st pocket has double the count of the others.
  123. ; at $1 == .66 the last half of all pockets have half the count of the 1st half of pockets.
  124. ; same bias exists in v6.35 except the valid range of random numbers is smaller
  125. ; for v6.35 9,14 must be changed to 9,12 and // floor divide changed to /
  126. ; You can edit the alias to change $rand to $randfix, which can also be edited to use any of
  127. ; the 3 versions of get_53bit_rand*. Beware the scripted $randfix replacement aliases is
  128. ; slower than $rand, but this is not a hardship for many scripts which use $rand rarely.
  129.  
  130. alias randbiasdemo {
  131. var %pct 0.996 | if (($1 > 0) && ($1 <= 1)) var %pct $1
  132. var -s %pockets 256 , %array $str(0 $chr(32),%pockets) , %i 25600 , %max $str(9,14) * %pct , %div %max / %pockets , %ticks $ticks
  133. while (%i) {
  134. var %t $calc(1+ ($randfix(0,%max) // %div)) , %a $gettok(%array,%t,32) + 1 , %array $puttok(%array,%a,%t,32)
  135. dec %i
  136. }
  137. echo -a time: $calc($ticks - %ticks) $+ ms
  138. echo -a %array = $calc($replace(%array,$chr(32),+))
  139. echo -a $stddev(%array)
  140. }
  141.  
  142. ; $stddev 1.0 by maroon
  143. ; takes space-delimited list of numbers
  144. ; The .prop is a format string delimited by periods. token beginning with 'label'
  145. ; is followed by literal text. numeric tokens round the next value's fraction.
  146. ; Inaccuracies can occur due to sums exceeding 2^53
  147. ;
  148. ; Valid keywords: sum mean stddev stderr
  149. ; sum = sum of all numbers
  150. ; mean = arithmetic mean. sum of values / count of values
  151. ; stddev = standard deviation
  152. ; stderr = 'standard error of the mean'
  153. ; examples
  154. ; as calculated by https://www.calculator.net/standard-deviation-calculator.html?numberinputs=1%2C+1%2C+2%2C+3%2C+5%2C+8%2C+13&x=76&y=12
  155. ; //echo -a $stddev(1 1 2 3 5 8 13)
  156. ; //echo -a $stddev(1 1 2 3 5 8 13).labelcount:.count.labelsum:.sum.labelPopulationVar:.3.popvar.labelSampleVar:.samplevar.labelPopStd-Dev:.popstddev.labelSampleStd-Dev:.samplestddev.labelStdError:.2.stderr
  157.  
  158. alias stddev {
  159. tokenize 32 $1- | if ($0 < 2) return | var %sum 0 , %sum.of.squares 0
  160. var %j $0 | while (%j) { inc %sum $gettok($1-,%j,32) | dec %j }
  161. var %mean %sum / $0
  162. var %j $0 | while (%j) {
  163. inc %sum.of.squares $calc( ($gettok($1-,%j,32) - %mean)^2 )
  164. dec %j
  165. }
  166. var %pop.variance $calc(%sum.of.squares / ($0 ))
  167. var %sample.variance $calc(%sum.of.squares / ($0 -1))
  168. var %pop.std.dev $calc((%sum.of.squares / ($0 ))^.5)
  169. var %sample.std.dev $calc((%sum.of.squares / ($0 -1))^.5)
  170. var %std.err $calc(%sample.std.dev / ($0 ^ .5) )
  171. if ($prop == $null) return count: $0 sum: %sum mean: %mean popvar: %pop.variance pop.stddev: %pop.std.dev sample.var: %sample.variance sample.std.dev: %sample.std.dev std.err: %std.err
  172. var %vals $0 %sum %mean %pop.variance %sample.variance %pop.std.dev %sample.std.dev %std.err, %i 0 , %t $numtok($prop,46) , %show , %round 99
  173. while (%i < %t) {
  174. inc %i | var %a $gettok($prop,%i,46) | if (%a isnum) var %round %a
  175. elseif (label* iswm %a) var %show %show $mid(%a,6)
  176. elseif ($findtok(count sum mean popvar samplevar popstddev samplestddev stderr,%a,1,32)) { var %show %show $round($gettok(%vals,$v1,32),%round) | var %round 99 }
  177. }
  178. return %show
  179. }
  180.  


Comments
No Comments.

Login to Comment.