#Help with Random Range Mathf function

1 messages · Page 1 of 1 (latest)

solid lion
#

I'm trying to write a function that outputs random values in the red regions. Given x and alpha are arbitrary float values. (See whiteboard photo)

The best I can come up with right now is this (see attached) But I'm pretty sure this becomes very inefficient/slow when the x is large and alpha is small. There has to be a better way so if anyone has a better idea I'm open to hear it

warm halo
#

Indeed that is an inefficient solution. The nature of randomness means that loop could be infinite. It's unlikely, but the mere fact that it's possible means you done a fuckup

#

It could forever generate values within the range of -x < n < x

#

A better (though probably not the best) solution, would be to generate two values.
First value would indicate whether you want to work with low range, or high range. You could just generate an integer for this, between 0 and 1 inclusive. 0 means work with range -x-alpha to -x, and 1 means work with range x to x+alpha

#

Then you just generate a second number, the float, working with the range that was decided

#

The problem with this approach is it strictly limits it to 2 ranges. It wouldn't be scalable to generate a float from, say, 100 different ranges (which you may want, who knows)

#

As an aside: UnityEngine.Random is poorly implemented, I recommend using .NET's built in RNG, System.Random. But that is unrelated to your issue

solid lion
#

so something like this?

warm halo
#

well, I would say don't cache to variables - just return the result directly. that way you aren't generating values that you throw away

#

but yes

#

that's the gist of it

warm halo
#

Problem there though, is the allocation of a list or array, which kills performance for an RNG which is something that should be extremely fast to do

solid lion
#

Thanks for the help! looking at my inital code I was thinking... there is no way this works well for all cases. Like it works decently for cases where x is small and alpha is large but terrible for cases x is large and alpha is small

warm halo
#

Though I guess you could take in a params array of tuples for min and max, randomly select an index, then randomly generate number between those min/max values

#

That would remove the whole allocation issue

solid lion
warm halo
#

Something like

float RandomFromRange(params (float Min, float Max)[] ranges)
{
    int index = Random.Range(0, ranges.Length);
    (float min, float max) = ranges[index];
    return Random.Range(min, max);
}

And you would be able to call like so:

float randomValue = RandomFromRange((-x - alpha, -x), (x, x + alpha));

NB: Untested. I wrote this code in Discord. But you shouldn't blindly copy/paste code anyway so y'know

#

One issue here would be possible exception if you call without giving it any ranges var

float randomValue = RandomFromRange();

would give you IndexOutOfRangeException since ranges.Length is 0, Random.Range(0, 0) would give you 0, and then ranges[0] would error out since there is no index 0

#

But you get the idea

sour coyote
#

Guys guys

warm halo
#

Oh no

#

Here's nt about to school us with Math™️

sour coyote
#

Just generate between -alpha and alpha. if the result is positive, add x. if the result is negative, subtract x

warm halo
#

That only works when you know the one of the ranges to be negative and the other to be positive

#

it wouldn't work for ranges (1, 10) and (20, 30), ignoring 11-19

#

Right? 🤔

#

Right

sour coyote
#

if you look at the original image, isn't the center of that range 0?

warm halo
#

LUL I had to think for a second there

sour coyote
#

like the ranges are symmetrical around zero

warm halo
#

It would be the center sure, assuming the upper bound of lower range is -x and lower bound of upper range is x

#

But what if the bounds aren't +-x?

sour coyote
#

who cares about a general solution lol, they specified this specific one

warm halo
#

kekw Well I care about a general solution

sour coyote
#

but if you'd like a general solution, you can get that too lol

warm halo
#

Because this kind of thing inspired me to add it to X10D. I wanted to come up with a general solution so that I could use it

sour coyote
#

okay let's say the upper bound of the lower range is a, and the lower bound of the upper range is b

#

then we want to generate from (a - alpha, a) U (b, b + alpha)
first, shift by the midpoint, aka, (a + b)/2. subtract all ranges by this midpoint value

(a - alpha - a/2 - b/2, a - a/2 - b/2) U (b - a/2 - b/2, b + alpha - a/2 - b/2)
(a/2 - b/2 - alpha, a/2-b/2) U (b/2 - a/2, b/2 - a/2 + alpha)

let y = b/2 - a/2. thus -y = a/2 - b/2. we can write
(-y - alpha, -y) U (y, y + alpha)

this is something we know how to solve. generate a random number R in (-alpha, alpha), then add y if R>0 or subtract y if R<0.

finally, to obtain the correct value, add y to our final result.

so the total code would be

float a = // ...
float b = // ...
float alpha = // ...
float mid = (a + b) / 2;
float diff = (b - a) /2;

float r = Random.Range(-alpha, alpha); // (-alpha, alpha)
if (r > 0) r += diff; // (b/2 - a/2, b/2 - a/2 + alpha)
if (r < 0) r -= diff; // (-alpha + a/2 - b/2, a/2 - b/2) 

return r + mid;
// upper: (b, b + alpha)
// lower: (-alpha + a, a)
sour coyote
#

Even more generally

const int rangeCount = // the number of ranges (can be more than 2)
float[] rangeStartPoints = // an array containing starting points of multiple ranges in ASCENDING order
float[] rangeLengths = // an array containing the length of the range

// the ith range begins at rangeStartPoints[i] and ends at rangeStartPoints[i] + rangeLengths[i]
// assume no range overlaps

float totalLength = 0;
for (var i = 0; i < rangeCount; i++)
{
  totalLength += rangeLengths;
}

void Generate()
{
  int index = 0;
  float r = Random.Range(0, totalLength);
  float currentLength = 0;
  for (; index < rangeCount; index++)
  {
    currentLength += rangeLengths[index];
    if (currentLength > r) break;
  }
  return rangeStartPoints[index] + currentLength - r;  
}
#

i bet chatgpt couldn't even write code that elegant

#

lol chatgpt can't figure out the algorithm

boreal elm
#

Can't you just do this?

return center + shift * (Random.Range(0, 1) * 2 - 1) + Random.Range(-range, range);
#

shift would be (2x + a) / 2, range would be a / 2, and center would be 0 using the first image as example

sour coyote
#

NOOOOOOOO

#
using System;

class Program
{
    static void Main(string[] args)
    {
        // Define ranges
        float[] rangeStartPoints = { 0f, 1.5f, 3f, 5f };
        float[] rangeLengths = { 1.5f, 1.5f, 2f, 3f };

        // Generate random number from ranges
        float randomNumber = GetRandomNumberInRange(rangeStartPoints, rangeLengths);

        // Print the result
        Console.WriteLine($"Random number: {randomNumber}");
    }

    static float GetRandomNumberInRange(float[] rangeStartPoints, float[] rangeLengths)
    {
        // Generate a random number between 0 and the total length of all ranges
        float totalLength = 0f;
        for (int i = 0; i < rangeLengths.Length; i++)
        {
            totalLength += rangeLengths[i];
        }
        float randomValue = (float)(new Random().NextDouble() * totalLength);

        // Find which range the random number falls into
        for (int i = 0; i < rangeStartPoints.Length; i++)
        {
            if (randomValue < rangeLengths[i])
            {
                // Random number falls within this range
                return rangeStartPoints[i] + randomValue;
            }
            else
            {
                randomValue -= rangeLengths[i];
            }
        }

        // This should never be reached, but just in case...
        throw new Exception("Unable to generate random number from ranges.");
    }
}

Generated from ChatGPT it did it more elegantly :(((

#

i've actually been replaced omg (actually I think the code has a bug tho)

sour coyote
boreal elm
#

Is it more expansive than using 2 loops with bunch of ifs though pikathink

sour coyote