Random() seems to be very biased towards positive numbers. how to mitigate?

My level of expertise is pretty low, I have some mild background in Java and QBasic way back when, and otherwise have learned most of the little I know via Daniel’s YT tuts (of which I’ve still many to go through).

But my main interest is playing around with random number generation and noise. I’ve noticed repeatedly that when I call for a random value in a manner such as “random(-5, 5)” for example, that the results tend to be very skewed towards the positive end of that range. Right now, I’m basically working with a simple randomly moving point atop a faint graph, and with the applied force that moves the point drawing from that pool of random values on each loop, the point invariably is in the bottom right quadrant (positive x value, positive y value) the vast majority of the time, even though in theory it should be pretty much evenly distributed across the quadrants. I find that to get something that feels more evenly distributed, I have to go with a range along the lines of (-7,5). Going to (-10, 5) it starts to skew too heavily into negatives, but anything less than about -7, positives will be disproportionately favored, it seems.

Any guidance on why this is or how to mitigate it? I know more or less how to use the “noise” function, but that’s not what I’m after here.

Thanks for anyone who can provide some clarity to this issue.

Ahh, 5 minutes after posting, I figure it out…

I tested the random function free of any other context, and got a much more even-seeming distribution of numbers. So checking my code more carefully, I realized the problem must stem from a bit I had added wherein on each loop, the random value (‘fsx’, and ‘fsy’) get divided by 2. Then I had added a modifier wherein once the value of either became less than .01, it reset to a new random # between -5 and 5.

Problem of course being that the negative values are always less than .01, creating a massive imbalance in how the code executes. Changing that bit of code to “abs(fsx)” fixed the issue.

I do feel like it still leans positive just a bit though, and part of the reason for the initial post was because it’s a tendency I’ve noticed repeatedly. But maybe in each case there was just a contextual factor contributing to that, as was the case here.

try this code

void setup() {
  int zero=0, positive=0, negative=0;
  final int totalTest = 1000000;

  for (int i=0; i < totalTest; i++) {
    float r = random(-100, 100);
    if (r == 0.0) zero++;
    else if (r > 0) positive++;
    else negative++;
  println("postive : ", positive, " (", ((float) positive) / totalTest, "%)");
  println("zero : ", zero, " (", ((float) zero) / totalTest, "%)");
  println("negative : ", negative, " (", ((float) negative) / totalTest, "%)");

void draw() {}

I get in the console:

postive : 500789 ( 0.500789%)
zero : 0 ( 0.0%)
negative : 499211 ( 0.499211%)

random() returns a float so The fact that 0.0 was never hit in one million draws is not surprising.

random() does not include the top value, so it’s not a totally fair interval. you have a bit more values below 0 than above zero but probably hard to notice

bumping totalTest to 1 000 000 000 (one billion tests) gave me

postive : 500009267 ( 0.5000093%)
zero : 59 ( 5.9E-8%)
negative : 499990674 ( 0.4999907%)

so this time I got a few (59) hits on 0.0 (at float precision)

You can see that this is fairly balanced between positive and negative in both cases anyway

1 Like

This old random walker sketch leaned positive so much I had to use some arbitrary value to subtract on the values returned from noise(): :bug:

  void move() {
    x += SPD * (noise(xoff += inc) - NOISE_OFFSET);
    y += SPD * (noise(yoff += inc) - NOISE_OFFSET);

may be… 500009267 positives versus 499990674 means it has been ~10,000 (9 296.5) times positive when it could have been negative for a correct balance on 1 billion draws --> that’s an error of less than 0.001% … not that bad.

static final float NOISE_OFFSET = JAVA? .4538 : .467;

we were talking random()

for the noise() function, the Perlin algorithm resulting value will always be between 0.0 and 1.0 - so it has to be stretched to your interval. As the doc states

There have been debates over the accuracy of the implementation of noise in Processing. For clarification, it’s an implementation of “classic Perlin noise” from 1983, and not the newer “simplex noise” method from 2001

Thanks for the information, Jay. I get the same result with your code. In fact, I get exactly the same result. I’m likely misunderstanding something, but shouldn’t the result be a little different each time the program is run?

As a side note, I had no idea you could abbreviate if/else if/else statements to the degree you do in that code. I thought you always needed curly-brackets.

Ah … it’s because of “randomSeed” that it’s the same result exactly, is that correct? I’m still wrapping my head around seeds and how they apply/work with noise/random. [Edit: just tested this w/ randomSeed commented out to confirm my own suspicions. So much to learn!]

If the true or false clause of an if statement has only one statement then you do not need to use braces (aka “curly brackets”).

This is considered dangerous though as it can lead to errors if you add more statements and do no realize the braces were not there, so most programming style guides recommend against doing so.

Yes the randomSeed thingy is not doing what I wanted with mouseX and Y to generate some randomness in the seed as it’s likely the mouse is not over the window in the setup and so you always get 0