Minimum and maximum random numbers

It seems like you want to select a random range that is between 45 and 90 wide and falls within a hue. Do you want ranges that can be centered on red? Hue is circular, so ranges from say 315-45 should be possible. Imagine yourself first picking a curved stick of random length 45-90, then placing it somewhere along the edge of a color wheel. Your current approach is to then chop off the right-hand side of the stick if it crosses over the line of absolute red (0/360). This means you have an unusually small number of ranges including the value 0/360, and an unusually large number of those have red as the last color-almost none have red as the first color. Do you want the possible results to be equally distributed?

This method gives you a normal distribution on 0-360 – so, almost no pure red, ever, but it is balanced.

float half = random(45, 90) / 2.0;  // half the range width
float center = random(0 + half, 360 - half);
float start = center - half;
float end = center + half;

Or you could just pick a random range.

float start = random(0, 360);
float end = (start + random(45, 90))%360;

This can give values like “[340, 20]” … but you might actually want that. If you intend to interpolate, you could also just skip the modulo and save “340, 380” as the range – interpolate, then use modulo before passing to a color function.

int[] range = new int[]{200, 400};
colorMode(HSB);
background(255);
for (int i=0; i<width; i++) {
  float c = lerp(range[0], range[1], i/(float)width);
  stroke(c%360, 255, 255);
  line(i, 0, i, height);
}

Another way to think about the constrain approach is that you have created a normal distribution from 0-405 (360+45) and then cropped it on the right side.

This shows the alternative to just make the result equally distributed – choose the size of the range first, then choose a valid random placement for your range based on its size. Now there are no hue ranges that cross red from either side.

/**
 * DistributeRandomRanges
 * 2020-01-06 Processing 3.4
 * https://discourse.processing.org/t/minimum-and-maximum-random-numbers/16888/4
 */
int[] hits;
int[] hits2;

void setup() {
  size(360, 360);
  hits = new int[360];
  hits2 = new int[360];
}

void draw() {
  background(255);
  PVector r = randomRange();
  for (int i=int(r.x); i<int(r.y); i++) {
    hits[i] = hits[i]+1;
  }
  PVector r2 = randomRange2();
  for (int i=int(r2.x); i<int(r2.y); i++) {
    hits2[i] = hits2[i]+1;
  }
  
  // draw current ranges
  stroke(255, 0, 0, 128);
  line(r.x, 20, r.y, 20);
  rect(width-45, 0, 45, height);  // problem on this end, see left edge
  stroke(0, 0, 255, 128);
  line(r2.x, 30, r2.y, 30);
    
  // draw cumulative graph of results
  for (int i=0; i<width; i++) {
    stroke(255, 0, 0, 128);
    line(i, height, i, height-hits[i]);
    stroke(0, 0, 255, 128);
    line(i, height, i, height-hits2[i]);
  }
}

PVector randomRange() { // @kll
  float rangemin=45, rangemax=90;
  float start, end;

  start = random(0, 360-rangemin);
  end  =  constrain(random(start+rangemin, start+rangemax), 0, 360); // thanks @Tiemen
  return new PVector(start, end);
}

PVector randomRange2() { // @jeremydouglass
  // the right hand side is correctly distributed
  float half = random(45, 90) / 2.0;
  float center = random(0 + half, 360 - half);
  float start = center - half;
  float end = center + half;
  return new PVector(start, end);
}

DistributeRandomRanges--screenshot

3 Likes