More precise % chances

I was wondering how to get more precise chances like 0.25%, 0.1%, by any easier means, or would I still have to use math.random?

local n = math.random(1, 100)

if n <= 25 then
    -- do thing that has 25% probability
else
    -- do other thing that has 75% probability 
end

Random object is easier to work with for smaller numbers

local r = Random.new()

local n = r:NextNumber(0, 1)

if n <= .25 then
    -- do thing that has 25% probability
else
    -- do other thing that has 75% probability 
end
1 Like
function randomNumber(min, max)
    return min + math.random() * (max - min)
end

This generates floating point decimal numbers so randomNumber(0, 100) could generate 0.00000001, which probably won’t happen, but it is possible.

1 Like

How would this function work?

30

oh boy… better to just use the Random object at that point so you can get a float from the NextNumber method if desired, or an int from the NextInteger method. 100x more readable too.

1 Like

Let’s say you want to do something with a 100% chance. First generate your number between 0 and 99: randomNumber(0, 99)
You can store this value however you want. But then you check if the number is less than the given value. Our case is 100 so:

local num = randomNumber(0, 99)
if num < 100 then
  -- Do whatever
end

Of course this will always be less than 100 because we’re generating from 0 to 99. This works the same with a 10% chance, if num < 10 same with 1% chance if num < 1 and .1% chance if num < .1 and so on.

We generate from 0 to 99 because that’s a range of 100 integers.

1 Like

This is how random number generation works in every other language than lua. This is the same formula used in C, C#, C++, Java, JavaScript, and so on. The math behind it is very simple and super fast. And you only need to make it a function once. Creating a new random means allocating memory to it. Which already makes it more inefficient for this.

Of course you can decide to use only one random and save it somewhere in a variable and use it constantly which would have better long term efficiency. But it is worth noting, Random:NextNumber(float, float) is [min, max) which means that percentage values wouldn’t actually be correct, even though they’d be off by a very small amount, they’re still wrong.

just because other langs use naïve rand()/srand() envelope multipliers doesn’t mean that’s the way it should be approached, especially in a high level scripting language designed around minimalistic readability.

Being concerned about a single object’s allocation is extreme preemptive micro optimization. I’d be surprised if it allocated even half a KB to create and store the Random object.

Not sure what you mean by this; using NextNumber is explicitly asking for a floating point result. if ran:NextNumber(0, 100) returns 51.932977730977; that’s still as above 50 as 52 is. If you want integers you use ran:NextInteger(0, 100)

The Random object allows you to create separate seeded buckets, including the ability to clone a constructed random object to copy it’s seed and current position. math.randomseed is globally applied, which really constrains it’s usability.

Everyone whos spent time with rand() knows LCG’s really suck. They’ve got a tendency to always return numbers within the first 40% of the envelope range.

The Random object uses a XSH-RR algorithm, which is a permuted congruential generator, instead of the linear congruential generator used in rand()/math.c’s math.random(), making it significantly more random than math.random is. (A Random Feature)

When you consider how much more readable the Random object syntax is, the significant versatility gap it has over math.random, as well as it just being better at being random, it doesn’t really make any sense to roll your own rand() envelope multiplier, or even use math.random at all for that matter.