Math.random higher!

How would i make a math.random, but the higher the number how more rare it is?

math.random(x, y) will give you random number between x and y. With equal probablity. So if you want make it so high number will be rare, you need use some math functions, like rooting, flooring.

local StartNum = math.random(1,1000)
local Result = math.floor(StartNum^0.5)

This function will make big number rare. Example:

math.random | Result
1           | 1
2-4         | 2
5-9         | 3
10-16       | 4
17-25       | 5
26-36       | 6
And so on.
2 Likes

Your explanation is good. However, there are a few things I’d like to mention about your answer.

Firstly, the uniform random number ranges for the result numbers in your example are incorrect. They would be correct if Result was math.ceil(StartNum^0.5), but in your code, Result is math.floor(StartNum^0.5).

Secondly, when generating random numbers, you probably want to be able to easily define the range in which these numbers are such that the result can be anywhere in this range but not outside the range. Your code gives integers from 1 to math.floor(1000^0.5) = 31 but this range is not explicitly specified. It’s just a result of the uniform random number range and the formula for getting Result.

Thirdly, of the numbers that your code can give as Result (integers from 1 to math.floor(1000^0.5)), the higher ones have higher probability (bigger range of uniformly chosen random numbers that result in the same Result). The goal was to have lower probability for higher numbers.

Here’s what I’d suggest.

-- uniformRandomValueModifier should give a value between 0 and 1 for any given value between 0 and 1.
local function getRandomValue(minValue, maxValue, uniformRandomValueModifier)
	local uniformRandomNumber = math.random()
	return minValue + uniformRandomValueModifier(uniformRandomNumber) * (maxValue - minValue)
end

-- You can change this as long as it gives a value between 0 and 1 for any given value between 0 and 1.
local function exampleModifierFunction(uniformRandomNumber)
	return uniformRandomNumber ^ 2
end

-- example usage
local randomNumberMoreLikelyToBeSmall = getRandomValue(1, 1000,  exampleModifierFunction)

You could also alternatively use an object of Random class for generating uniform random numbers but whether it is more handy than math.random() depends on the use case.

2 Likes

could I also make the chanve even smaller because im stil getting high numbers

Increasing the exponent to something higher than 2 is a simple way to make high numbers more rare. Of course, you can also use some other kind of function.

Edit:
If you want to have a lot of control over the distribution, you can decide a probability density function and calculate the random variable based on that. I will probably write more about this later (maybe tomorrow).

Edit:
Continuous probability distribution
Here’s the explanation about defining and using a probability density function. Let f(x) be the probability density function where x is a possible value of the random variable. The greater the value of f(x) at a given x, the greater is the probability of a random sample being a value close to x (assuming that the density function is continuous near x). The probability of any single value, however, is 0 in a continuous probability distribution because the number of possible values is infinite.

The probability of a random sample being less than or equal to a given x is the area bounded by the density function (which I call f) curve and x-axis in the interval ]-inf, x]. This can be calculated as the definite integral of f from -inf to x.

Let F(x) (notice the capital letter, lowercase f denotes the density function) be the function whose value is the definite integral of f in the interval ]-inf, x]. So, given an x, F(x) will give the probability of a sample being less than x. Let’s call this probability p. We now have F(x) = p. When we have the expression of F (expression of the definite integral in terms of x), if we can solve x in terms of p from the equation, we can form the inverse function of F. Let’s call this inverse function g(p). Given a probability p ((0 <= p <= 1 because probability must be between 0 and 1), g(p) will give us a sample value.

So, we can generate random numbers that follow the distribution defined by the density function by generating a uniform random probability p (with math.random() for example) and calculating g(p).

There are some requirements for the density function.

  1. The values must be non-negative. This is because probabilities are non-negative which means that the signed area between the density function f curve and x-axis must be non-negative in any interval, which is only satisfied if all the values are non-negative.
  2. The area bounded by the function curve and x-axis in the interval ]-inf, inf[ must be 1 because samples can’t be less than -inf or more than inf which means that the probability of them being between -inf and inf must be 1 (probability 1 (100 %) means certain).

I’ll explain a possible way to get a function that satisfies requirement 2. Let’s say you have an expression 1 / (abs(x) + 1)^2. This can only have positive values so this satisfies the first condition. The definite integral of this in the interval ]-inf, inf[ is 2, which is more than 1 so this does not satisfy the second condition. However, you can decide that f(x) = a * (1 / (abs(x) + 1)^2) where a is such a number that f(x) can be used as a density function. You can then solve a from the following equation:
Density function multiplier equation

By solving this equation, we get a = 1/2. Thus, f(x) = 1/2 * (1 / (abs(x) + 1)^2) is a valid probability density function.

Discrete probability distribution
I decided to write a little about discrete probability distributions as well. If you want to have a finite number of discrete values as possible values for the random variable (for example, integers in an interval), you can just assign a weight for each possible number, and the probability of that number being chosen as a sample is proportional to the weight. There are other posts in the forum about choosing weighted random values.

If you want a discrete distribution with infinite possible values that start from some value (for example, all positive integers), you can probably achieve that if the probabilities form a number sequence that satisfies the following conditions:

  1. Sum from the first index to a given index i can be calculated without calculating the members before i (at least geometric sequences satisfy this (and arithmetic sequences, but they don’t satisfy condition 3)).
  2. i can be solved in terms of p from the equation S(i) = p where S(i) is the aforementioned sum.
  3. The sum S(inf) must be 1 (right kind of geometric sequences can satisfy this).

Conclusion
If you haven’t learned integrals and sums of number sequences in school yet, then it may be better to stick with a more simple approach:

  • arbitrarily choosing a somewhat good function for a continuous distribution like in my earlier post
  • assigning weights for possible values for a discrete distribution with a inite number of possible sample values.
3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.