问题
Edit: This is using Google Chrome 36
I was messing around with html5 canvas, generating points randomly distributed inside a cube and projecting that onto a 2D canvas. Surprisingly, the results don't look very symmetric at all, and I suspect that Javascript's Math.random() is letting me down.
Can anyone tell me why this is happening? Is it possible to make it actually look random, without making it slower?
var ctx = canvas.getContext('2d');
for (var i = 0; i < 10000000; i++) {
var x = Math.random()*2-1, y = Math.random()*2-1, z = 2+Math.random()*2-1;
x = (.5 + .5*x/z) * canvas.width;
y = (.5 + .5*y/z) * canvas.height;
ctx.fillRect(Math.floor(x), Math.floor(y), 1, 1);
}
http://jsfiddle.net/y10tvj26/ (Takes a while to load)
回答1:
Chrome has a documented issue that subsequent calls to Math.random() are correlated. In your algorithm, correlated values will tend to fall on a line on the canvas. An extra call to Math.random() breaks that correlation. I haven't seen reports that other browsers are affected.
Just call Math.random()
an extra time on each call, and you'll get what you want.
var ctx = canvas.getContext('2d');
function r() {
Math.random();
return Math.random();
}
for (var i=0; i<10000000; i++) {
var x = r()*2-1, y = r()*2-1, z = 2+r()*2-1;
x = (.5 + .5*(x/z)) * canvas.width;
y = (.5 + .5*(y/z)) * canvas.height;
ctx.fillRect(x, y, 1, 1);
}
Updated on: http://jsfiddle.net/y10tvj26/5/
回答2:
This is a case of pseudorandom number generation vs. random generation. Basically, there are numbers that will occur more often than others when you generate pseudorandom numbers (such as with the Math.random() function). See here for more information about the difference.
As far as actually making it look more "random", I would note that for a smaller range of i the image does look random, it's only when you choose a very large value that the flaws become apparent. Additionally, I don't believe seting your own seed for Math.random will be an adequate solution either, because you will still see degradation in the "randomness" when you iterate a very large number of times.
A potential solution would be to use a different library to generate pseudorandom numbers and see if it produces a better looking output. Other than that, you're pretty much constrained to the deterministic properties of computers (at least until powerful quantum computers show up on the market!).
Edit - This problem is unique to Google Chrome's implementation of Math.random() and documented in the following locations: Why is Google Chrome's Math.random number generator not *that* random? https://code.google.com/p/chromium/issues/detail?id=276886 https://code.google.com/p/v8/issues/detail?id=558
来源:https://stackoverflow.com/questions/25272799/why-does-this-random-distribution-look-asymmetric