Skip to content

Instantly share code, notes, and snippets.

@Zirak
Last active December 16, 2015 20:19
Show Gist options
  • Select an option

  • Save Zirak/5491248 to your computer and use it in GitHub Desktop.

Select an option

Save Zirak/5491248 to your computer and use it in GitHub Desktop.
//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