Advertisement
Guest User

Untitled

a guest
Jul 8th, 2013
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.70 KB | None | 0 0
  1. -- analysis of "random" number generator
  2.  
  3. -- ... Seed values?
  4. -- .... oh god no
  5. local ran = math.random()
  6. local r = math.random()
  7. local ra = math.random(1,15)
  8.  
  9. function genNumber()
  10.   local rand = nil
  11.  
  12.   -- Programming error: Could just use "return value" instead of setting a
  13.   -- local variable
  14.   if ra == 1 then
  15.     -- rand(1, 9) * 10 + r, typed as a string
  16.     -- Extremely badly distributed, as it only returns 9 distinct values.
  17.     rand = math.random(1,9)..r
  18.   elseif ra == 2 then
  19.     -- Bell-curve distribution, due to addition of two evenly distributed
  20.     -- variables.
  21.     -- Returns one distinct value.
  22.     rand = r+ran
  23.   elseif ra == 3 then
  24.     -- Bell-curve distribution, due to subtraction of two evenly distributed
  25.     -- variables.
  26.     -- Returns one distinct value.
  27.     rand = r-ran
  28.   elseif ra == 4 then
  29.     -- I-have-no-idea distribution. Limited to range [0, 1]
  30.     -- Still only returns one distinct value
  31.     rand = r*ran
  32.   elseif ra == 5 then
  33.     -- Another I-have-no-idea distribution.
  34.     -- Returns only one distinct number
  35.     rand = r/ran
  36.   elseif ra == 6 then
  37.     -- Another I-have-no-idea distribution.
  38.     -- Returns only one distinct number
  39.     rand = math.pow(r,ran)
  40.   elseif ra == 7 then
  41.     -- ....??
  42.     -- Returns only one distinct number
  43.     rand = math.sqrt(r)
  44.   elseif ra == 8 then
  45.     -- Always 1
  46.     rand = math.ceil(r)
  47.   elseif ra == 9 then
  48.     -- Always 0
  49.     rand = math.floor(r)
  50.   elseif ra == 10 then
  51.     -- Returns only one distinct number still
  52.     rand = r
  53.   else
  54.     -- Really...? Returns very high numbers. Still only one distinct value
  55.     rand = ra/r
  56.   end
  57.  
  58.   -- Conclusion: Total of 23 distinct return values... assuming that ra is
  59.   -- randomly chosen... Since it's only chosen once per library load, as
  60.   -- well as the other values, this function only ever returns one value.
  61.  
  62.   -- See: http://xkcd.com/221/
  63.  
  64.   return rand
  65. end
  66.  
  67. function genBetween(min,max)
  68.   -- Oh hey, this one is actually random every call! :D
  69.   -- I can actually analyze this as a random function!
  70.   local b = math.random(min,max)
  71.   local be2 = math.random(min,max)
  72.   local be3 = math.random(1,15)
  73.  
  74.   -- Programming error: be4 is not local, and will leak into the environment.
  75.   be4 = nil
  76.  
  77.   if be3 == 1 then
  78.     -- Horrible distribution. As it's generated via string concatation, the
  79.     -- "lower half" of the distribution is confined in a way that is... hard
  80.     -- to mathematically qualify.
  81.  
  82.     -- Probably translates to: be2*(10^ceil(ln(b)/ln(10))) + b
  83.     be4 = be2..b
  84.   elseif be3 == 2 then
  85.     -- Bell curve distribution. Has a range of [min*2,max*2]
  86.     be4 = b+be2
  87.   elseif be3 == 3 then
  88.     -- Bell curve distribution. Has a range of [0, max-min]
  89.     be4 = b-be2
  90.   elseif be3 == 4 then
  91.     -- Screwed up distribution. Has a range of [min*min, max*max]
  92.     be4 = b*be2
  93.   elseif be3 == 5 then
  94.     -- I'm not even going to try and analyse this. Why would you ever use an
  95.     -- division operation on random numbers, as part of a generator?
  96.  
  97.     -- Also, this can return NaN, and other nastiness in the case of an range
  98.     -- containing zero.
  99.     be4 = b/be2
  100.   elseif be3 == 6 then
  101.     -- This is liable to produce very very huge values.
  102.     -- Values like "inf" which are not very friendly to the code that comes
  103.     -- after this.
  104.     be4 = math.pow(b,be2)
  105.   elseif be3 == 7 then
  106.     -- This operation makes no sense, and doesn't even have a chance of adding
  107.     -- any entropy to b.
  108.     be4 = math.sqrt(b)
  109.   elseif be3 == 8 then
  110.     -- b is an integer value. This has no effect.
  111.     be4 = math.ceil(b)
  112.   elseif be3 == 9 then
  113.     -- b is an integer value. This has no effect.
  114.     be4 = math.floor(b)
  115.   elseif be3 == 10 then
  116.     -- ...??
  117.     be4 = b
  118.   else
  119.     -- Identical to be3 == 5
  120.     -- Again, has a weird distribution that I won't try to qualify.
  121.     be4 = b/be2
  122.   end
  123.  
  124.   -- Huge programming error:
  125.  
  126.   -- All of this is horrible.
  127.   -- Replace it with: return ((math.floor(be4)-min)%(max-min))+min
  128.  
  129.   -- This solves this function returning floating point values (!!!), as well
  130.   -- as it returning values outside the stated range. It does not solve the
  131.   -- problem that you've utterly screwed up the random function.
  132.   if be4 > max then
  133.     -- The value can very well exceed max*2 at this point, and this won't help
  134.     -- in the majority of cases.
  135.  
  136.     -- You want the modulo operation here.
  137.     local be5 = be4-max
  138.  
  139.     -- Because the else clause returns just be4, this is broken. The obvious
  140.     -- use of this function will get "max" back, which is clearly not what
  141.     -- is intended. Instead, the "random" value is stuck in the second return
  142.     -- slot.
  143.  
  144.     -- Effectively, you have to do this to get the true "random" value:
  145.     -- local a, b = genBetween(min, max)
  146.     -- if b then
  147.     --   a = b
  148.     -- end
  149.     return max, be5
  150.   else
  151.     -- You arn't going to try to do anything with values under min!?!?
  152.     return be4
  153.   end
  154. end
  155.  
  156. -- To illustrate what's wrong with this code, here's a graph of frequency of
  157. -- various return values, in the range [0, 255], with my modification so that
  158. -- the return values were even in the right range:
  159. -- http://www.chartgo.com/share.do?id=8c8b8a22aa
  160.  
  161. -- Entropy analysis on a similar sample:
  162.  
  163. --[[
  164.    Entropy = 6.125075 bits per byte.
  165.    
  166.    Optimum compression would reduce the size
  167.    of this 4084095 byte file by 23 percent.
  168.    
  169.    Chi square distribution for 4084095 samples is 76378531.33, and randomly
  170.    would exceed this value 0.01 percent of the times.
  171.    
  172.    Arithmetic mean value of data bytes is 62.9531 (127.5 = random).
  173.    Monte Carlo value for Pi is 3.802550971 (error 21.04 percent).
  174.    Serial correlation coefficient is 0.001314 (totally uncorrelated = 0.0).
  175. ]]--
  176.  
  177. -- Now let's compare with math.random!
  178.  
  179. --[[
  180.    Entropy = 7.999952 bits per byte.
  181.  
  182.    Optimum compression would reduce the size
  183.    of this 4194304 byte file by 0 percent.
  184.  
  185.    Chi square distribution for 4194304 samples is 276.68, and randomly
  186.    would exceed this value 25.00 percent of the times.
  187.  
  188.    Arithmetic mean value of data bytes is 127.4833 (127.5 = random).
  189.    Monte Carlo value for Pi is 3.137709749 (error 0.12 percent).
  190.    Serial correlation coefficient is 0.000921 (totally uncorrelated = 0.0).
  191. ]]--
  192.  
  193. -- Well then... looks like this version is less random.
  194. -- I would have tried to analyse the original version too, but, that would be
  195. -- extremely difficult due to the extreme range of numbers returned... because
  196. -- genBetween generates a huge number of values outside the supposed "min" and
  197. -- "max" values. Whoops!!!
  198.  
  199. -- The thing is, randomness doesn't work like this. For one, to be "useful",
  200. -- the numbers must be "evenly distributed". That is, that graph above? A truly
  201. -- random sequence would have a flat line, as there's no bias towards any
  202. -- particular value.
  203.  
  204. -- To be useful, randomness must be predictable in some quality, that is, it
  205. -- returns a known set of values (either a floating point value between 0 and
  206. -- 1, or an integer value between two chosen points), while having an even
  207. -- distribution between those values, while still being unpredictable, as far
  208. -- as knowing /which value/ will be chosen goes.
  209.  
  210. -- As far as combining values goes, this doesn't help randomness, because, you
  211. -- can't pull information/randomness out of thin air. It has to come from
  212. -- somewhere. In this case, Java uses an PRNG called an LCG to generate its
  213. -- random numbers. It's very not random, and has 32 bits of state. Pulling more
  214. -- values from it does not magically make a "more random" value.
  215.  
  216. -- Further reading:
  217. --   https://en.wikipedia.org/wiki/Entropy_(information_theory)
  218. --   https://en.wikipedia.org/wiki/Information_theory
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement