Linear Regression in Javascript [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I want to do Least Squares Fitting in Javascript in a web browser.
Currently users enter data point information using HTML text inputs and then I grab that data with jQuery and graph it with Flot.
After the user had entered in their data points I would like to present them with a "line of best fit". I imagine I would calculate the linear, polynomial, exponential and logarithmic equations and then choose the one with the highest R^2 value.
I can't seem to find any libraries that will help me to do this though. I stumbled upon jStat, but it is completely missing documentation (as far as I can find) and after digging through the the source code it doesn't seem to have any linear regression functionality built in--I'm basing this purely on function names however.
Does anyone know any Javascript libraries that offer simple regression analysis?
The hope would be that I could use the library like so...
If I had some set of scatter points in an array var points = [[3,4],[15,45],...[23,78]], I would be able to hand that to some function like lin_reg(points) and it would return something like [7.12,3] if the linear equation was y = 7.12 x + 3.

What kind of linear regression? For something simple like least squares, I'd just program it myself:
http://mathworld.wolfram.com/LeastSquaresFitting.html
The math is not too hard to follow there, give it a shot for an hour or so and let me know if it's too hard, I can try it.
EDIT:
Found someone that did it:
http://dracoblue.net/dev/linear-least-squares-in-javascript/159/

The simplest solution I found for the question at hand can be found in the following post:
http://trentrichardson.com/2010/04/06/compute-linear-regressions-in-javascript/
Note that in addition to the linear equation, it also returns the R2 score, which can be useful.
** EDIT **
Here is the actual code snippet:
function linearRegression(y,x){
var lr = {};
var n = y.length;
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var sum_yy = 0;
for (var i = 0; i < y.length; i++) {
sum_x += x[i];
sum_y += y[i];
sum_xy += (x[i]*y[i]);
sum_xx += (x[i]*x[i]);
sum_yy += (y[i]*y[i]);
}
lr['slope'] = (n * sum_xy - sum_x * sum_y) / (n*sum_xx - sum_x * sum_x);
lr['intercept'] = (sum_y - lr.slope * sum_x)/n;
lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y)/Math.sqrt((n*sum_xx-sum_x*sum_x)*(n*sum_yy-sum_y*sum_y)),2);
return lr;
}
To use this you just need to pass it two arrays, known_y's and known_x's, so this is what you might pass:
var known_y = [1, 2, 3, 4];
var known_x = [5.2, 5.7, 5.0, 4.2];
var lr = linearRegression(known_y, known_x);
// now you have:
// lr.slope
// lr.intercept
// lr.r2

I found this great JavaScript library.
It's very simple, and seems to work perfectly.
I also can't recommend Math.JS enough.

Simple linear regression with measures of variation ( Total sum of squares = Regression sum of squares + Error sum of squares ), Standard error of estimate SEE (Residual standard error), and coefficients of determination R2 and correlation R.
const regress = (x, y) => {
const n = y.length;
let sx = 0;
let sy = 0;
let sxy = 0;
let sxx = 0;
let syy = 0;
for (let i = 0; i < n; i++) {
sx += x[i];
sy += y[i];
sxy += x[i] * y[i];
sxx += x[i] * x[i];
syy += y[i] * y[i];
}
const mx = sx / n;
const my = sy / n;
const yy = n * syy - sy * sy;
const xx = n * sxx - sx * sx;
const xy = n * sxy - sx * sy;
const slope = xy / xx;
const intercept = my - slope * mx;
const r = xy / Math.sqrt(xx * yy);
const r2 = Math.pow(r,2);
let sst = 0;
for (let i = 0; i < n; i++) {
sst += Math.pow((y[i] - my), 2);
}
const sse = sst - r2 * sst;
const see = Math.sqrt(sse / (n - 2));
const ssr = sst - sse;
return {slope, intercept, r, r2, sse, ssr, sst, sy, sx, see};
}
regress([1, 2, 3, 4, 5], [1, 2, 3, 4, 3]);

Check out
https://web.archive.org/web/20150523035452/https://cgwb.nci.nih.gov/cgwbreg.html (javascript regression calculator) - pure JavaScript, not CGI calls to server. The data and processing remains on your computer. Complete R style results and R code to check the work and a visualization of the results.
See the source code for the embedded JavaScript implementations of OLS and statistics associated with the results.
The code is my effort to port the GSL library functions to JavaScript.
The codes is released under GPL because it's basically line for line porting of GPL licensed Gnu Scientific Library (GSL) code.
EDIT: Paul Lutus also provides some GPL code for regression at: http://arachnoid.com/polysolve/index.html

Here is a snippet that will take an array of triplets (x, y, r) where r is the weight of the (x, y) data point and return [a, b] such that Y = a*X + b approximate the data.
// return (a, b) that minimize
// sum_i r_i * (a*x_i+b - y_i)^2
function linear_regression( xyr )
{
var i,
x, y, r,
sumx=0, sumy=0, sumx2=0, sumy2=0, sumxy=0, sumr=0,
a, b;
for(i=0;i<xyr.length;i++)
{
// this is our data pair
x = xyr[i][0]; y = xyr[i][1];
// this is the weight for that pair
// set to 1 (and simplify code accordingly, ie, sumr becomes xy.length) if weighting is not needed
r = xyr[i][2];
// consider checking for NaN in the x, y and r variables here
// (add a continue statement in that case)
sumr += r;
sumx += r*x;
sumx2 += r*(x*x);
sumy += r*y;
sumy2 += r*(y*y);
sumxy += r*(x*y);
}
// note: the denominator is the variance of the random variable X
// the only case when it is 0 is the degenerate case X==constant
b = (sumy*sumx2 - sumx*sumxy)/(sumr*sumx2-sumx*sumx);
a = (sumr*sumxy - sumx*sumy)/(sumr*sumx2-sumx*sumx);
return [a, b];
}

Somewhat based on Nic Mabon's answer.
function linearRegression(x, y)
{
var xs = 0; // sum(x)
var ys = 0; // sum(y)
var xxs = 0; // sum(x*x)
var xys = 0; // sum(x*y)
var yys = 0; // sum(y*y)
var n = 0;
for (; n < x.length && n < y.length; n++)
{
xs += x[n];
ys += y[n];
xxs += x[n] * x[n];
xys += x[n] * y[n];
yys += y[n] * y[n];
}
var div = n * xxs - xs * xs;
var gain = (n * xys - xs * ys) / div;
var offset = (ys * xxs - xs * xys) / div;
var correlation = Math.abs((xys * n - xs * ys) / Math.sqrt((xxs * n - xs * xs) * (yys * n - ys * ys)));
return { gain: gain, offset: offset, correlation: correlation };
}
Then y' = x * gain + offset.

Related

Fit a quantity of items to a binomial distribution / bell curve [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 1 year ago.
Improve this question
This is a sort of discrete math integration question - I need to fit a fixed quantity of items to a binomial distribution or bell curve over a fixed period.
Say I a total of M boxes being shipped over T days, where n is the number boxes that arrive on day t. I need a way to calculate n(t) for each day t, so that
The Sum ( n(t) ) 0 -> t = M
t is an integer, and n(t) is an integer, and
the shape of n(t) matches as closely as possible to a bell curve.
Edit
In case anyone does think this an SO-worthy question, here's the Javascript I cobbled together from the pointers in Yves Daoust answer.
/*
See https://stackoverflow.com/questions/5259421/
*/
function normal(x, mean, stdDev) {
return stdNormal(( x - mean ) / stdDev);
}
function stdNormal(z) {
// Power series is not stable at these extreme tail scenarios
if (z < -6) { return 0; }
if (z > 6) { return 1; }
let j, k ;
let m = 1; // m(k) == (2**k)/factorial(k)
let b = z; // b(k) == z ** (2*k + 1)
let z2 = z * z; // cache of z squared
let z4 = z2 * z2; // cache of z to the 4th
let values = [];
// Compute the power series in groups of two terms.
// This reduces floating point errors because the series
// alternates between positive and negative.
for (k=0; k<100; k+=2) {
const a = 2*k + 1;
let item = b / (a*m);
item *= (1 - (a*z2)/((a+1)*(a+2)));
values.push(item);
m *= (4*(k+1)*(k+2));
b *= z4;
}
// Add the smallest terms to the total first that
// way we minimize the floating point errors.
let total = 0;
for (k=49; k>=0; k--) {
total += values[k];
}
// Multiply total by 1/sqrt(2*PI)
// Then add 0.5 so that stdNormal(0) === 0.5
return 0.5 + 0.3989422804014327 * total;
}
/*
Compute the cdf of the binomial distribution between 0 and T, times M.
Round all values to integers. Let m(t) the numbers so obtained.
Use n(t) = m(t+1) - m(t). In doing so, you ensure Σ n(t) = n(T) - n(0) = M.
Thanks to Yves Daoust
*/
function distributeItems(itemsToPlace = 100, steps = 7) {
const mean = Math.floor((steps - 1) / 2);
const stdDev = mean / 2.96; /// for 'standard' std dev ;-)
const m = [0]; // cdf
const n = [0]; // items
for (var step = 1; step <= steps; step++) {
m.push(Math.round(normal(step, mean, stdDev) * itemsToPlace,0));
n.push( m[step] - m[step - 1] );
}
const interimCount = n.reduce(function (sum, elt) { return sum+elt; }, 0);
const discrepancy = itemsToPlace - interimCount;
if (discrepancy !==0) {
n[n.length-1] += discrepancy;
}
return n;
}
const n = distributeItems(40,7);
console.log('Items: ',n, 'Total: ',n.reduce(function (sum, elt) { return sum+elt; }, 0))
// Result
// [ 0, 1, 5, 14, 14, 5, 1, 0 ] 40
Maybe not an optimal solution, but should not be far.
Compute the cdf of the binomial distribution between 0 and T, times M.
Round all values to integers. Let m(t) the numbers so obtained.
Use n(t) = m(t+1) - m(t). In doing so, you ensure Σ n(t) = n(T) - n(0) = M.
In the picture below, the blue curve is an exact binomial N=7, p=0.3, adjusted for M=20. The orange curve is obtained by the above procedure. As you can check, 2+5+6+4+2+1+0+0=20.

Costumize indicators from stock tools

I'm trying to implement some technical indicators series and add them to the indicators popop from stock tools. If I import highcharts/indicators/indicators-all I end up getting dozens of indicators, so I figured to import only the ones I need, so far I wasn't able to achieve that, if I import highcharts/indicators/indicators I end up getting only SMA, I tried to import other technical indicators via highcharts/indicators/indicators-INDICATOR-NAME but it didn't work.
Besides that I'd like to create a technical indicator/function such as Linear Regression (from this example) and attach them to the indicators popup as well.
function getLinearRegression(xData, yData) {
var sumX = 0,
sumY = 0,
sumXY = 0,
sumX2 = 0,
linearData = [],
linearXData = [],
linearYData = [],
n = xData.length,
alpha,
beta,
i,
x,
y;
// Get sums:
for (i = 0; i < n; i++) {
x = xData[i];
y = yData[i];
sumX += x;
sumY += y;
sumXY += x * y;
sumX2 += x * x;
}
// Get slope and offset:
alpha = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
if (isNaN(alpha)) {
alpha = 0;
}
beta = (sumY - alpha * sumX) / n;
// Calculate linear regression:
for (i = 0; i < n; i++) {
x = xData[i];
y = alpha * x + beta;
// Prepare arrays required for getValues() method
linearData[i] = [x, y];
linearXData[i] = x;
linearYData[i] = y;
}
return {
xData: linearXData,
yData: linearYData,
values: linearData
};
}
Is that even possible?
Live Demo
EDIT
To add a specific technical indicator you should add as an import highcharts/indicators/NAME (highcharts/indicators/ema,
highcharts/indicators/rsi e.g.)
That feature is not implemented in stock tools, but it could be very useful so you can create a new feature request here: https://github.com/highcharts/highcharts/issues/new/choose
Workaround:
All indicator series from plot options are added to stock tools, so you can customize chart.options.plotOptions, for example in load event:
chart: {
events: {
load: function() {
var plotOptions = this.options.plotOptions,
filteredSeries = {};
Highcharts.objectEach(plotOptions, function(option, key) {
if (!option.params || key === 'dema' || key === 'customlinearregression') {
filteredSeries[key] = option;
}
});
this.options.plotOptions = filteredSeries;
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/xwec9hr7/2/
Useful example: https://www.highcharts.com/stock/demo/stock-tools-custom-gui
Code reference: https://github.com/highcharts/highcharts/blob/371424be0b168de96aa6a58b81ce0b2b7f40d5c5/ts/annotations/popup.ts#L783

JavaScript Math.random Normal distribution (Gaussian bell curve)?

I want to know if the JavaScript function Math.random uses a normal (vs. uniform) distribution or not.
If not, how can I get numbers which use a normal distribution? I haven't found a clear answer on the Internet, for an algorithm to create random normally-distributed numbers.
I want to rebuild a Schmidt-machine (German physicist). The machine produces random numbers of 0 or 1, and they have to be normally-distributed so that I can draw them as a Gaussian bell curve.
For example, the random function produces 120 numbers (0 or 1) and the average (mean) of these summed values has to be near 60.
Since this is the first Google result for "js gaussian random" in my experience, I feel an obligation to give an actual answer to that query.
The Box-Muller transform converts two independent uniform variates on (0, 1) into two standard Gaussian variates (mean 0, variance 1). This probably isn't very performant because of the sqrt, log, and cos calls, but this method is superior to the central limit theorem approaches (summing N uniform variates) because it doesn't restrict the output to the bounded range (-N/2, N/2). It's also really simple:
// Standard Normal variate using Box-Muller transform.
function gaussianRandom(mean=0, stdev=1) {
let u = 1 - Math.random(); //Converting [0,1) to (0,1)
let v = Math.random();
let z = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
// Transform to the desired mean and standard deviation:
return z * stdev + mean;
}
Normal Distribution Between 0 and 1
Building on Maxwell's Answer, this code uses the Box–Muller transform to give you a normal distribution between 0 and 1 inclusive. It just resamples the values if it's more than 3.6 standard deviations away (less than 0.02% chance).
function randn_bm() {
let u = 0, v = 0;
while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while(v === 0) v = Math.random();
let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
num = num / 10.0 + 0.5; // Translate to 0 -> 1
if (num > 1 || num < 0) return randn_bm() // resample between 0 and 1
return num
}
Visualizations
n = 100
n = 10,000
n = 10,000,000
Normal Distribution With Min, Max, Skew
This version allows you to give a min, max, and skew factor. See my usage examples at the bottom.
function randn_bm(min, max, skew) {
let u = 0, v = 0;
while(u === 0) u = Math.random() //Converting [0,1) to (0,1)
while(v === 0) v = Math.random()
let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v )
num = num / 10.0 + 0.5 // Translate to 0 -> 1
if (num > 1 || num < 0)
num = randn_bm(min, max, skew) // resample between 0 and 1 if out of range
else{
num = Math.pow(num, skew) // Skew
num *= max - min // Stretch to fill range
num += min // offset to min
}
return num
}
randn_bm(-500, 1000, 1);
randn_bm(10, 20, 0.25);
randn_bm(10, 20, 3);
Here is the JSFiddle for these screenshots: https://jsfiddle.net/2uc346hp/
I want to know if the JavaScript function Math.random is normal distribution or not
Javascript Math.random is not a Normal Distribution(Gaussian bell curve). From ES 2015, 20.2.2.27 "Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. This function takes no arguments." So the provided collection when n is high enough we will get approximately uniform distribution. All values in the interval will have equal probability of appearance(straight line parallel to the x axis, denoting number between 0.0 and 1.0).
how can I get numbers which are normal distribution
There are several ways of getting collection of numbers with a normal distribution. As answered by Maxwell Collard the Box-Muller transform
does transform uniform distribution to normal distribution(the code can be found in Maxwell Collard answer).
An answer to another stackoverflow answer to a question has a reply with other uniform distribution to normal distribution algorithms. Such as:
Ziggurat,
Ratio-of-uniforms,
Inverting the CDF
Besides one of the answers says that: says:
The Ziggurat algorithm is pretty efficient for this, although the Box-Muller transform is easier to implement from scratch (and not crazy slow).
And finally
I want to rebuilt a Schmidt-machine (German physicist), the machine produces random numbers of 0 or 1 and they have to be normal distributed so I can draw them in Gaussian bell curve.
When we have only two values (0 or 1) Gaussian curve looks the same as uniform distribution with 2 possible values. That is why a simple
function randomZero_One(){
return Math.round(Math.random());
}
would suffice. It would return pseudo-randomly with approximately equal probability values 0 and 1.
I wanted to have approximately gaussian random numbers between 0 and 1, and after many tests I found this to be the best:
function gaussianRand() {
var rand = 0;
for (var i = 0; i < 6; i += 1) {
rand += Math.random();
}
return rand / 6;
}
And as a bonus:
function gaussianRandom(start, end) {
return Math.floor(start + gaussianRand() * (end - start + 1));
}
The Javascript Math.random() pseudorandom function returns variates that are equally distributed between 0 and 1. To get a Gaussian distribution I use this:
// returns a gaussian random function with the given mean and stdev.
function gaussian(mean, stdev) {
var y2;
var use_last = false;
return function() {
var y1;
if (use_last) {
y1 = y2;
use_last = false;
} else {
var x1, x2, w;
do {
x1 = 2.0 * Math.random() - 1.0;
x2 = 2.0 * Math.random() - 1.0;
w = x1 * x1 + x2 * x2;
} while (w >= 1.0);
w = Math.sqrt((-2.0 * Math.log(w)) / w);
y1 = x1 * w;
y2 = x2 * w;
use_last = true;
}
var retval = mean + stdev * y1;
if (retval > 0)
return retval;
return -retval;
}
}
// make a standard gaussian variable.
var standard = gaussian(100, 15);
// make a bunch of standard variates
for (i = 0; i < 1000; i++) {
console.log( standard() )
}
I think I got this from Knuth.
Plot can be seen here
Function that utilises the central limit theorem.
function normal(mu, sigma, nsamples){
if(!nsamples) nsamples = 6
if(!sigma) sigma = 1
if(!mu) mu=0
var run_total = 0
for(var i=0 ; i<nsamples ; i++){
run_total += Math.random()
}
return sigma*(run_total - nsamples/2)/(nsamples/2) + mu
}
From the spec:
15.8.2.14 random ( )
Returns a Number value with positive sign, greater than or equal to 0
but less than 1, chosen randomly or pseudo randomly with
approximately uniform distribution over that range, using an
implementation-dependent algorithm or strategy. This function takes no
arguments.
So, it's a uniform distribution, not normal or Gaussian. That's what you're going to find in just about any standard random number facility in any basic language runtime outside of specialized statistics libraries.
You are confusing the output of the function (which is a uniform distribution between 0 and 1) with the need to generate a Gaussian distribution by repeatedly drawing random numbers that are either 0 or 1 - after a large number of trials, their sum will be approximately normally distributed.
You can use the Math.random() function, then round the result to an integer: if it's < 0.5, return 0; if its >= 0.5, return 1. Now you have equal probabilities of zero and one, and you can continue with the approach you described in your question.
Just to clarify: I don't think it's possible to have an algorithm that produces either 0's or 1's in a normally distributed way - normal distribution requires a continuous variable.
When you do the above for say 120 numbers, you will on average get 60 1's and 60 0's. The actual distribution you get will be the binomial distribution with a mean of 60 and a standard deviation of
stdev = sqrt(p(1-p)N) = 5.48
The probability of a particular number k when you have n samples with probability p (which we fixed at 0.5) is
p = n! / ((n-k)! k!) p^k (1-p)^(n-k)
When p = 0.5, you end up with just the binomial coefficients - which approach the normal distribution for n > 30, typically.
And a single line example:
Math.sqrt(-2 * Math.log(Math.random()))*Math.cos((2*Math.PI) * Math.random())
and a Fiddle
https://jsfiddle.net/rszgjqf8/
For those interested in generating values of a normal distrubution, I would recommend checking this implementation of the Ziggurat algorithm in JavaScript: https://www.npmjs.com/package/node-ziggurat
The code of found in the author's page is:
function Ziggurat(){
var jsr = 123456789;
var wn = Array(128);
var fn = Array(128);
var kn = Array(128);
function RNOR(){
var hz = SHR3();
var iz = hz & 127;
return (Math.abs(hz) < kn[iz]) ? hz * wn[iz] : nfix(hz, iz);
}
this.nextGaussian = function(){
return RNOR();
}
function nfix(hz, iz){
var r = 3.442619855899;
var r1 = 1.0 / r;
var x;
var y;
while(true){
x = hz * wn[iz];
if( iz == 0 ){
x = (-Math.log(UNI()) * r1);
y = -Math.log(UNI());
while( y + y < x * x){
x = (-Math.log(UNI()) * r1);
y = -Math.log(UNI());
}
return ( hz > 0 ) ? r+x : -r-x;
}
if( fn[iz] + UNI() * (fn[iz-1] - fn[iz]) < Math.exp(-0.5 * x * x) ){
return x;
}
hz = SHR3();
iz = hz & 127;
if( Math.abs(hz) < kn[iz]){
return (hz * wn[iz]);
}
}
}
function SHR3(){
var jz = jsr;
var jzr = jsr;
jzr ^= (jzr << 13);
jzr ^= (jzr >>> 17);
jzr ^= (jzr << 5);
jsr = jzr;
return (jz+jzr) | 0;
}
function UNI(){
return 0.5 * (1 + SHR3() / -Math.pow(2,31));
}
function zigset(){
// seed generator based on current time
jsr ^= new Date().getTime();
var m1 = 2147483648.0;
var dn = 3.442619855899;
var tn = dn;
var vn = 9.91256303526217e-3;
var q = vn / Math.exp(-0.5 * dn * dn);
kn[0] = Math.floor((dn/q)*m1);
kn[1] = 0;
wn[0] = q / m1;
wn[127] = dn / m1;
fn[0] = 1.0;
fn[127] = Math.exp(-0.5 * dn * dn);
for(var i = 126; i >= 1; i--){
dn = Math.sqrt(-2.0 * Math.log( vn / dn + Math.exp( -0.5 * dn * dn)));
kn[i+1] = Math.floor((dn/tn)*m1);
tn = dn;
fn[i] = Math.exp(-0.5 * dn * dn);
wn[i] = dn / m1;
}
}
zigset();
}
Create a Ziggurat.js file and then:
var z = new Ziggurat();
z.nextGaussian();
For me it's working just perfect and as I had read in Wikipedia, this is a more efficient algorithm than the Box-Muller.
enter link description here
I have tested several functions with the right configuration all work similarly and well.
http://jsfiddle.net/p3y40gf3/29/
Central limit is nice, must be with (n=3 for 6) and 12 for 12 to look as others. I configured others also to (6) or 12 or 1/12 as standard deviation, not sure why 12.
Central limit is a tiny bit less centered than Box/Muller and Ziggurat.
Box/Muller and Ziggurat look exactly the same
this variant by Joe(https://stackoverflow.com/a/33567961/466363) does standard deviation correctly:
function normal(mu, sigma, nsamples){ // using central limit
if(!nsamples) nsamples = 3
if(!sigma) sigma = 1
if(!mu) mu=0
var run_total = 0
for(var i=0 ; i<nsamples ; i++){
run_total += Math.random()
}
return sigma*(run_total - nsamples/2)/(nsamples/2) + mu
}
Ziggurat is also nice but needs to be adjusted from z score to from 0 to 1 looks like it makes good numbers.
Box/Muller clipped is good but gives few repeated numbers at clipped edges
but it is very similar to others,
incorrect random numbers should be discarded not clipped.
function randn_bm() {
var u = 0, v = 0;
while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while(v === 0) v = Math.random();
let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
num = num / 6.0 + 0.5; // Translate to 0 -> 1 // changed here 10 to 6
if(num>1||num<0) return randn_bm(); return num; // bad random numbers should be discared not clipped
//return Math.max(Math.min(num, 1), 0); // cap between 0 and 1
}
Central limit variant it is called Bates distribution that is average
https://en.wikipedia.org/wiki/Bates_distribution
not confused with Irwin Hall that is a sum
https://en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution
https://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution
A non verbose function to sample a random value from a Gaussian distribution I wrote some time ago:
function gaussianRandom(mean, sigma) {
let u = Math.random()*0.682;
return ((u % 1e-8 > 5e-9 ? 1 : -1) * (Math.sqrt(-Math.log(Math.max(1e-9, u)))-0.618))*1.618 * sigma + mean;
}
It should work if you clamp the values to the range you want.
skewnormal from normal and normal01
skewnormal(min, max, ..) returns a random number from the normal distribution that has been streched and offset to range from min to max, exponentially skewed with skew, and truncated to sigma standard deviations (in reverse order). Broken up into logical steps normal and normal01 for clarity and to generate random numbers directly from these intermediate functions if desired. (Plus a bonus lognormal!)
/// skewnormal(..) returns a random number from the normal distribution that has
/// been streched and offset to range from `min` to `max`, skewed with `skew`,
/// and truncated to `sigma` standard deviations. See https://stackoverflow.com/a/74258559/213246
const skewnormal = (min, max, skew = 1, sigma = 8) => {
/// normal() returns a random number from the standard normal distribution.
/// Uses the Box-Muller transform.
const normal = () => Math.sqrt(-2.0 * Math.log(Math.random())) * Math.cos(2.0 * Math.PI * Math.random());
/// normal01(..) returns normally distributed random number, whose range is
/// truncated at `sigma` standard deviations and shifted to interval `[0, 1]`.
const normal01 = (sigma) => {
while (true) {
let num = normal() / (sigma + 0.0) + 0.5; // translate to [0, 1]
if (0 <= num && num <= 1) return num; // ok if in range, else resample
}
}
var num = normal01(sigma);
num = Math.pow(num, skew) // skew
num *= max - min // stretch to fill range
num += min // offset to min
return num;
}
/// lognormal() returns a random number from the log-normal distribution.
const lognormal = () => Math.exp(normal());
Based on another popular answer by joshuakcockrell. You may prefer this implementation because: 1. it's factored to portray intermediate functions, 2. it exposes mathematically relevant and useful sigma parameter, 3. it has better names and comments.
See the JSFiddle for the complete demo environment, which makes it easy to define then test and visualize your own random distribution functions as pictured below:
View interactive charts: https://jsfiddle.net/rgefzusq/34/show/ Playground: https://jsfiddle.net/rgefzusq/34/
This is my JavaScript implementation of Algorithm P (Polar method for normal deviates) from Section 3.4.1 of Donald Knuth's book The Art of Computer Programming:
function gaussian(mean, stddev) {
return function() {
var V1
var V2
var S
do{
var U1 = Math.random()
var U2 = Math.random()
V1 = 2*U1-1
V2 = 2*U2-1
S = V1*V1+V2*V2
}while(S >= 1)
if(S===0) return 0
return mean+stddev*(V1*Math.sqrt(-2*Math.log(S)/S))
}
}
Use it like that:
var standard_normal = gaussian(0,1)
var a_standard_normal_deviate = standard_normal()
I found this library that includes lots of useful Random functions. You can either install it via simjs from npm, or just take the random-node-*.js file out directly for what you need.
http://www.simjs.com/random.html
http://www.simjs.com/download.html
This is my solution to the problem, using the Marsaglia polar method. The range depends on the parameters you give, without parameters it almost never generates anything outside of the range.
As it generates two normally distributed numbers per iteration, I declared a variable under window.temp.spareNormal to grab the spare one if it's there. Might not be the best location for it, but hey.
You'd probably have to round the result in order to get what you want.
window.temp = {
spareNormal: undefined
};
Math.normal = function (mean, standardDeviation) {
let q, u, v, p;
mean = mean || 0.5;
standardDeviation = standardDeviation || 0.125;
if (typeof temp.spareNormal !== 'undefined') {
v = mean + standardDeviation * temp.spareNormal;
temp.spareNormal = undefined;
return v;
}
do {
u = 2.0 * Math.random() - 1.0;
v = 2.0 * Math.random() - 1.0;
q = u * u + v * v;
} while (q >= 1.0 || q === 0);
p = Math.sqrt(-2.0 * Math.log(q) / q);
temp.spareNormal = v * p;
return mean + standardDeviation * u * p;
}
for finding normal distribution of value:
getNormal = (x, mean, standardDeviation, ) => {
return (1 / standardDeviation * Math.sqrt(2 * (3, 14))) * Math.pow(Math.E, -Math.pow(x - mean, 2) / (2 * (standardDeviation * standardDeviation)));
}
The only sort of qualifications I have for this is having taken a single statistics class. If I get something wrong, please tell me, I'd like to learn more about statistics and I don't want to keep thinking something wrong.
If you want to create a random number generator that produces numbers in a normal distribution, you should be able to take samples from a uniform distribution, which is no problem. If you set up a basic random number generator that generates numbers in range a to b, the distribution of values produced will have µ = (a+b)/2 and σ = (b-a)/√12. If the mean of a a few sample of values (≥30) taken from this distribution is taken for many such samples, then for the sampling distribution µ (sample means) = µ (population mean) and σ (sample means' stdev) = σ (population stdev)/√n (number of values in the sample).
By controlling the mean and stdev of the original distribution, you can control the ending mean and standard deviation of a random number generator that produces a normal distribution.
function all_normal(mu, sigma, nsamp)
{
var total = 0;
for (var a = 0; a < nsamp; a ++)
{
total += rand_int(mu - (sigma * Math.sqrt(3 * nsamp)), mu + (sigma * Math.sqrt(3 * nsamp)));
}
return Math.ceil(total / nsamp);
}
Just in case: Math.pow(Math.random(), p).
For example:
function testR(max = 100, min = 0, p = 1, c = 20)
{
let t = [];
for (let i = 0; i < c; ++i)
{
t.push(Math.floor(Math.pow(Math.random(), p) * (max - min + 1) + min));
}
console.log(
`p = ${String(p).padStart(5)}`, '|',
t.sort(function (a, b) { return a - b; }).join(', ')
);
}
testR(9, 0, 10);
testR(9, 0, 2);
testR(9, 0, 1);
testR(9, 0, 0.5);
testR(9, 0, 0.1);
testR(9, 0, 0.05);
Results in client/JS console
jsFiddle graph test:
let iset = 0;
let gset;
function randn() {
let v1, v2, fac, rsq;
if (iset == 0) {
do {
v1 = 2.0*Math.random() - 1.0;
v2 = 2.0*Math.random() - 1.0;
rsq = v1*v1+v2*v2;
} while ((rsq >= 1.0) || (rsq == 0));
fac = Math.sqrt(-2.0*Math.log(rsq)/rsq);
gset = v1*fac;
iset = 1;
return v2*fac;
} else {
iset = 0;
return gset;
}
}
//This is what I use for a Normal-ish distribution random function.
function normal_random(){
var pos = [ Math.random(), Math.random() ];
while ( Math.sin( pos[0] * Math.PI ) > pos[1] ){
pos = [ Math.random(), Math.random() ];
}
return pos[0];
};
This function returns a value between 0 and 1. Values near 0.5 are returned most often.

ACE Text Editor displays text characters in place of spaces

I've written the following Javascript:
(function () {
var computationModule = (function foo1(stdlib, foreign, heap) {
"use asm";
var sqrt = stdlib.Math.sqrt,
heapArray = new stdlib.Int32Array(heap),
outR = 0.0,
outI = 0.0;
function computeRow(canvasWidth, canvasHeight, limit, max, rowNumber, minR, maxR, minI, maxI) {
canvasWidth = +canvasWidth;
canvasHeight = +canvasHeight;
limit = +limit;
max = max | 0;
rowNumber = +rowNumber;
minR = +minR;
maxR = +maxR;
minI = +minI;
maxI = +maxI;
var columnNumber = 0.0,
zReal = 0.0,
zImaginary = 0.0,
numberToEscape = 0;
var columnNumberInt = 0;
// Compute the imaginary part of the numbers that correspond to pixels in this row.
zImaginary = +(((maxI - minI) * +rowNumber) / +canvasHeight + minI);
// Iterate over the pixels in this row.
// Compute the number of iterations to escape for each pixel that will determine its color.
for (columnNumber = +0; + columnNumber < +canvasWidth; columnNumber = +(+columnNumber + 1.0)) {
// Compute the real part of the number for this pixel.
zReal = +(((maxR - minR) * +columnNumber) / +canvasWidth + minR);
numberToEscape = howManyToEscape(zReal, zImaginary, max, limit) | 0;
columnNumberInt = columnNumberInt + 1 | 0;
heapArray[(columnNumberInt * 4) >> 2] = numberToEscape | 0;
}
}
// Function to determine how many iterations for a point to escape.
function howManyToEscape(r, i, max, limit) {
r = +r;
i = +i;
max = max | 0;
limit = +limit;
var j = 0,
ar = 0.0,
ai = 0.0;
ar = +r;
ai = +i;
for (j = 0;
(j | 0) < (max | 0); j = (j + 1) | 0) {
iteratingFunction(ar, ai, r, i)
ar = outR;
ai = outI;
if (+(ar * ar + ai * ai) >= +(limit * limit))
return j | 0;
}
return j | 0;
}
// The iterating function defining the fractal to draw
// r and i are the real and imaginary parts of the value from the previous iteration
// r0 and i0 are the starting points
function iteratingFunction(r, i, r0, i0) {
r = +r;
i = +i;
r0 = +r0;
i0 = +i0;
computePower(r, i, 2);
// Set the output from this function to t
outR = +(r0 + outR);
outI = +(i0 + outI);
}
// Compute the result of [r,i] raised to the power n.
// Place the resulting real part in outR and the imaginary part in outI.
function computePower(r, i, n) {
// Tell asm.js that r, i are floating point and n is an integer.
r = +r;
i = +i;
n = n | 0;
// Declare and initialize variables to be numbers.
var rResult = 0.0;
var iResult = 0.0;
var j = 0;
var tr = 0.0;
var ti = 0.0;
// Declare and initialize variables that will be used only in the
// event we need to compute the reciprocal.
var abs = 0.0;
var recr = 0.0;
var reci = 0.0;
if ((n | 0) < (0 | 0)) {
// For n less than 0, compute the reciprocal and then raise it to the opposite power.
abs = +sqrt(r * r + i * i);
recr = r / abs;
reci = -i / abs;
r = recr;
i = reci;
n = -n | 0;
}
rResult = r;
iResult = i;
for (j = 1;
(j | 0) < (n | 0); j = (j + 1) | 0) {
tr = rResult * r - iResult * i;
ti = rResult * i + iResult * r;
rResult = tr;
iResult = ti;
}
outR = rResult;
outI = iResult;
} // end computePower
return {
computeRow: computeRow
};
})(self, foreign, heap);
// Return computationModule that we just defined.
return computationModule;
})();
There's nothing particularly unusual about this Javascript, except that I want to make my web application display the Javascript in an ACE text editor (http://ace.c9.io/) so that the user can modify the code at runtime.
I load the Javascript using jQuery AJAX and then set the contents of the ACE Editor to the Javascript code. After the user modifies the code, he can click a button to run the code. (This uses eval)
The problem I'm having is that ACE is displaying strange characters instead of spaces.
Oddly enough, if I try to copy text from the ACE editor, the strange characters disappear and the spaces are normal. Furthermore, the code runs fine even with these strange characters being displayed.
I also noticed that the problem does not appear when using Firefox, but it appears for Chrome and IE 11.
Finally, the problem only occurs when I put the code on a real web server. It doesn't reproduce in my development environment.
Looking at this some more, I can see that it's not just the text I'm loading via AJAX. Even when I type new spaces, more text characters appear!
What could be going wrong so that the text doesn't display properly?
Here's a link to the application: http://danielsadventure.info/html5fractal/
Use charset="utf-8" in the script tag where you include ace.
<script src="path/to/ace.js" charset="utf-8">
This may have something to do with this:
When no explicit charset parameter is provided by the sender, media
subtypes of the "text" type are defined to have a default charset
value of "ISO-8859-1" when received via HTTP. Data in character sets
other than "ISO-8859-1" or its subsets MUST be labeled with an
appropriate charset value. See section 3.4.1 for compatibility
problems.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
So the string passed to the script are in an encoding different than what ACE (or JS in general) expects, which is UTF-8.

is there a JavaScript implementation of the Inverse Error Function, akin to MATLAB erfinv()?

is there a JavaScript implementation of the Inverse Error Function?
This would implement the Gauss inverse error function. Approximations are ok.
Why yes. There is.
The following code uses built-in JavaScript functions and implments Abramowitz and Stegun's algorithm as described here:
function erfinv(x){
var z;
var a = 0.147;
var the_sign_of_x;
if(0==x) {
the_sign_of_x = 0;
} else if(x>0){
the_sign_of_x = 1;
} else {
the_sign_of_x = -1;
}
if(0 != x) {
var ln_1minus_x_sqrd = Math.log(1-x*x);
var ln_1minusxx_by_a = ln_1minus_x_sqrd / a;
var ln_1minusxx_by_2 = ln_1minus_x_sqrd / 2;
var ln_etc_by2_plus2 = ln_1minusxx_by_2 + (2/(Math.PI * a));
var first_sqrt = Math.sqrt((ln_etc_by2_plus2*ln_etc_by2_plus2)-ln_1minusxx_by_a);
var second_sqrt = Math.sqrt(first_sqrt - ln_etc_by2_plus2);
z = second_sqrt * the_sign_of_x;
} else { // x is zero
z = 0;
}
return z;
}
function provided earlier in this post did not work for me... NaN result on a 33meter circle with confidence 65% represented as 65.0 ... I wrote the following based on an equation listed here https://en.wikipedia.org/wiki/Error_function#Inverse_functions and it worked fine:
var _a = ((8*(Math.PI - 3)) / ((3*Math.PI)*(4 - Math.PI)));
function erfINV( inputX )
{
var _x = parseFloat(inputX);
var signX = ((_x < 0) ? -1.0 : 1.0 );
var oneMinusXsquared = 1.0 - (_x * _x);
var LNof1minusXsqrd = Math.log( oneMinusXsquared );
var PI_times_a = Math.PI * _a ;
var firstTerm = Math.pow(((2.0 / PI_times_a) + (LNof1minusXsqrd / 2.0)), 2);
var secondTerm = (LNof1minusXsqrd / _a);
var thirdTerm = ((2 / PI_times_a) + (LNof1minusXsqrd / 2.0));
var primaryComp = Math.sqrt( Math.sqrt( firstTerm - secondTerm ) - thirdTerm );
var scaled_R = signX * primaryComp ;
return scaled_R ;
}
Here's an alternative implementation of Abramowitz and Stegun's algorithm (equivalent to ptmalcolm's answer, but more succinct and twice as fast):
function erfinv(x) {
// maximum relative error = .00013
const a = 0.147
//if (0 == x) { return 0 }
const b = 2/(Math.PI * a) + Math.log(1-x**2)/2
const sqrt1 = Math.sqrt( b**2 - Math.log(1-x**2)/a )
const sqrt2 = Math.sqrt( sqrt1 - b )
return sqrt2 * Math.sign(x)
}
You can test the speed with console.time("erfinv"); for (let i=0; i<1000000000; i++) {erfinv(i/1000000000)}; console.timeEnd("erfinv")
The if statement optimization is commented out as it doesn't seem to make a difference - presumably the interpreter recognizes that this is all one equation.
If you need a more accurate approximation, check out Wikipedia.

Categories

Resources