Support for normal random distribution #2700
Replies: 19 comments
-
This is indeed quite strange. It's still in the code, has been in parts ported over to v2's new infrastructure and there exist unit tests for it, but it isn't wired up. Also it is used with In my opinion it's a bug in one of two ways:
@josdejong: Any thoughts? |
Beta Was this translation helpful? Give feedback.
-
Sorry for the confusion, it shouldn't have been in the docs. The code of |
Beta Was this translation helpful? Give feedback.
-
Any news on this front? |
Beta Was this translation helpful? Give feedback.
-
My $0.02: /**
* Returns a random number with a Normal distribution
* @param {float} min
* @param {float} max
* @param {int} precision Optional, will increase the number of iterations.
**/
function normalRandom(min, max, precision) {
min = min ? min : 0;
max = max ? max : 1;
precision = precision ? precision : 6;
var rand = 0;
for (var i = 0; i < precision; i += 1) {
rand += Math.random();
}
return (rand / precision)*(max-min)+min;
}
math.import({
"normalRandom": normalRandom
}); Credits for the function go to http://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/39187274#39187274 |
Beta Was this translation helpful? Give feedback.
-
Personally, I prefer the Box-Muller transform. It is more exact, and produces two independent normally distributed variables at a time, There is a good implementation in Numerical Recipes which avoids the evaluation of cosine and sine, and caches the second calculated variable for the next time the function is called. Really quite neat! |
Beta Was this translation helpful? Give feedback.
-
Thanks! Please do forgive me my ignorance, but what do you mean by Numerical Recipes? http://numerical.recipes? The same StackOverflow page gave me this: function normalRandom() {
var u = 1 - Math.random(); // Subtraction to flip [0, 1) to (0, 1].
var v = 1 - Math.random();
return Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
} I don't see how anything could be cached in this function. |
Beta Was this translation helpful? Give feedback.
-
Numerical Recipes is a collection of highly optimized algorithms for C and Fortran, but I just realized you need a license to use the programs directly. I think our best option would be to refer to this article on Wikipedia, which gives the polar form of the Box-Muller transform (which is also the form used in numerical recipes): https://en.wikipedia.org/wiki/Marsaglia_polar_method The code sample from StackOverflow, Essentially, you choose a random point in the unit circle (by choosing a point in a square and rejecting it if it is outside the circle). Then, by some clever transformation, the x and y values of that point are converted into two normally distributed random variables. You can use caching with either the original form or the polar form, since both forms produce two variables that are independent, or not related upon each other. For reference, here is the code sample from Wikipedia: double generateGaussianNoise(const double& mean, const double &stdDev)
{
static bool hasSpare = false;
static double spare;
if(hasSpare)
{
hasSpare = false;
return mean + stdDev * spare;
}
hasSpare = true;
static double u, v, s;
do
{
u = (rand() / ((double) RAND_MAX)) * 2.0 - 1.0;
v = (rand() / ((double) RAND_MAX)) * 2.0 - 1.0;
s = u * u + v * v;
}
while( (s >= 1.0) || (s == 0.0) );
s = sqrt(-2.0 * log(s) / s);
spare = v * s;
return mean + stdDev * u * s;
} |
Beta Was this translation helpful? Give feedback.
-
Thanks again. What about this? /**
* Returns a random number with a Normal distribution
* @param {float} min The minimum value (default: 0)
* @param {float} max The maximum value (default: 1)
* @param {float} stdDev The standard deviation (default: 10% of max-min).
**/
function normalRandom(min, max, stdDev) {
min = min ? min : 0;
max = max ? max : 1;
stdDev = stdDev ? stdDev : (max-min)*0.10;
var mean = (min + max) / 2;
var spare;
var u, v, s;
var randomValue;
if(typeof window.mathjs_normalRandom_spare !== 'undefined') {
randomValue = mean + stdDev * window.mathjs_normalRandom_spare;
delete window.mathjs_normalRandom_spare;
}else{
do {
u = Math.random() * 2 - 1;
v = Math.random() * 2 - 1;
s = u * u + v * v;
}while((s >= 1.0) || (s === 0));
s = Math.sqrt(-2.0 * Math.log(s) / s);
window.mathjs_normalRandom_spare = v * s;
randomValue = mean + stdDev * u * s;
}
return randomValue;
} I'm not sure about keeping min, max and about the default standard deviation. For my own use case I just need a min and max and in a way its nice to keep the function similar to the 'normal' random function. What do you think? |
Beta Was this translation helpful? Give feedback.
-
That's looking good. I'll let @josdejong comment on the use of global (static) variables; I'm not sure what his preference is on that. I wonder if it would be better to use Also, be careful using |
Beta Was this translation helpful? Give feedback.
-
Thanks @koosvanderkolk! The usage of a global @koosvanderkolk would you be interested in working your solution out in a pull request? (that would be awesome) |
Beta Was this translation helpful? Give feedback.
-
Thanks for your response! What about the arguments provided to normalRandom? Should these become function normalRandom(mean, stdDev) { And is 'normalRandom' the right function name? I had a look at https://github.com/josdejong/mathjs/blob/master/lib/function/probability/seededRNG.js, but I'm not entirely sure whether I understand what is happening there.... And isn't this singletonRandom a global var as well? |
Beta Was this translation helpful? Give feedback.
-
The ugly |
Beta Was this translation helpful? Give feedback.
-
Thanks! About this pull request: I do have some time left, but could you provide me some guidance on the path to take? Mathjs is quite a overwhelming piece of code :-). E.g. my current plan would be:
|
Beta Was this translation helpful? Give feedback.
-
It may be easiest to copy for example the Docs for a function are automatically generated from the code comments: just keep the structure that's there in For unit tests, you can copy Please don't hesitate to ask if you have more questions! |
Beta Was this translation helpful? Give feedback.
-
What is the status of this? |
Beta Was this translation helpful? Give feedback.
-
This issue is stil open, I think Koos didn't manage to implement this, I haven't heard back. Anyone interested in picking this up? |
Beta Was this translation helpful? Give feedback.
-
The project for which this was needed was suddenly cancelled, so I had to move on. I would be happy to put some effort in it, but would still be struggling on how to implement the global var ("mathjs_normalRandom_spare" in my script) in a mathjs-way... |
Beta Was this translation helpful? Give feedback.
-
Thanks for your update Koos. Please don't feel obligated to pick this up, only if you enjoy it :). Since we had this discussion, we have had quite a deep change in the dependency injection solution of mathjs (since v6.0.0), it's good to be aware of that. I don't know the exact details of |
Beta Was this translation helpful? Give feedback.
-
It looks like
distribution()
was removed for rethinking. However, it still exists in the docs.Curious, is there a work around for doing random number generation with normal distribution without this method? Thanks much.
Beta Was this translation helpful? Give feedback.
All reactions