Last active
December 16, 2015 20:19
-
-
Save Zirak/5491248 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //once again, scroll to the bottom | |
| var stat = {}; | |
| //the arithmetic mean. takes nargs or an array | |
| //passing in 0 numbers is undefined behaviour | |
| // μ = (x0 + x1 + ... + xn) / n | |
| stat.mean = function (x) { | |
| var nums = Array.isArray(x) ? x : arguments, | |
| sum = 0; | |
| for (var i = 0; i < nums.length; i += 1) { | |
| sum += nums[i]; | |
| } | |
| return sum / i; | |
| }; | |
| //the unbiased (n-1) variance. takes nargs or an array. | |
| // σ² = (x0 - μ)² + ... + (xn - μ)² | |
| // σ²(1, 2, 3, 4, 5) = 2.5 | |
| stat.variance = function (x) { | |
| var nums = Array.isArray(x) ? x : [].slice.call(arguments), | |
| mean = stat.mean(nums), | |
| sum = 0; | |
| for (var i = 0; i < nums.length; i += 1) { | |
| sum += Math.pow(nums[i] - mean, 2); | |
| } | |
| return sum / (i - 1); | |
| }; | |
| //the standard deviation σ | |
| // σ(1, 2, 3, 4, 5) = 2.5² = 6.25 | |
| stat.sd = function () { | |
| return Math.sqrt(this.variance.apply(this, arguments)); | |
| }; | |
| //the frequency of x in nums | |
| //if x is an array and nums is not passed in, | |
| // returns an object with the frequency of each item | |
| // freq(1, [0, 1, 2, 1, 8, 4]) === 2 | |
| // freq([0, 1, 2, 1, 8, 4]) === {0:1, 1:2, 2:1, 4:1, 8:1} | |
| stat.freq = function (x, nums) { | |
| if (nums === undefined && Array.isArray(x)) { | |
| var ret = {}, y; | |
| for (var i = 0; i < x.length; i += 1) { | |
| y = x[i]; | |
| if (!ret.hasOwnProperty(y)) { | |
| ret[y] = 0; | |
| } | |
| ret[y] += 1; | |
| } | |
| return ret; | |
| } | |
| return nums.reduce(function (ret, y) { | |
| return ret + (x === y); | |
| }, 0); | |
| }; | |
| //the relative frequency of x in nums | |
| //follows same argument logic as freq | |
| // relfreq(1, [0, 1, 2, 1, 8, 4, 1, 2]) === 0.375 | |
| // relfreq([0, 1, 2, 1, 8, 4, 1, 2]) === | |
| // {0: 0.125, 1: 0.375, 2: 0.25, 4: 0.125, 8: 0.125} | |
| stat.relfreq = function (x, nums) { | |
| if (nums === undefined && Array.isArray(x)) { | |
| var freq = this.freq(x), | |
| n = x.length | |
| return Object.keys(freq).reduce(function (ret, y) { | |
| ret[y] = freq[y] / n; | |
| return ret; | |
| }, {}); | |
| } | |
| return this.freq(x, nums) / nums.length; | |
| }; | |
| stat.random = {}; | |
| //the entropy of data according to Shannon's entropy. if a string is passed, it | |
| // is broken down into its corresponding char-codes | |
| //lim(entropy) = 8 | |
| stat.random.entropy = function (data) { | |
| if (data.split) { | |
| data = data.split('').map(function (c) { return c.charCodeAt(0); }); | |
| } | |
| var relfreqs = stat.relfreq(data); | |
| return Object.keys(relfreqs).reduce(function (entropy, key) { | |
| var p = relfreqs[key] | |
| if (p) { | |
| ////we want the base 2 logarihm of p. unfortunately, in js there's | |
| // only the natural logarithm, but that's easily ammendable | |
| entropy -= p * (Math.log(p) / Math.LN2) | |
| } | |
| return entropy; | |
| }, 0); | |
| }; | |
| //tests start here | |
| var guid = function() { | |
| function sect(l) { | |
| var radix = Math.random() * 26 + 11|0; | |
| return Date.now().toString(radix).substr(-l); | |
| } | |
| return [sect(8), sect(4), sect(4), sect(4), sect(12)].join('-'); | |
| }; | |
| var guidRand = function() { | |
| function sect(l) { | |
| var radix = Math.random() * 26 + 11|0; | |
| return Date.now().toString(radix).split('').sort(function() { return Math.round(Math.random())-0.5 }).join('').substr(-l); | |
| } | |
| return [sect(8), sect(4), sect(4), sect(4), sect(12)].join('-'); | |
| }; | |
| function test (fun) { | |
| var hash = {}, | |
| entropies = [], | |
| i = 0, id; | |
| var s = Date.now(), time, col = true; | |
| while (true) { | |
| if (!(i % 1000)) { | |
| console.log(i); | |
| time = Date.now(); | |
| //if it took us more than 5 seconds to run 1000 loops, terminate | |
| if (time - s >= 5000) { | |
| col = false; | |
| break; | |
| } | |
| s = time; | |
| } | |
| id = fun(); | |
| if (hash[id]) break; | |
| hash[id] = true; | |
| entropies[i] = stat.random.entropy(id); | |
| i += 1; | |
| } | |
| if (col) { | |
| console.log('collision after %s', i); | |
| } | |
| else { | |
| console.log('test terminated before collision was found'); | |
| } | |
| console.log('mean entropy: ' + stat.mean(entropies)); | |
| console.log('σ: ' + stat.sd(entropies)); | |
| } | |
| //test(guid); | |
| test(guidRand); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment