Course: PHP

Progress (0%)

# PHP Random Numbers

Chapter 15 15 mins

Learning outcomes:

1. What are pseudo-random numbers
2. The `rand()` function
3. The `mt_rand()` function
4. Seeding via `srand()` or `mt_srand()`
5. Random float in the range `[0, 1)`

## Introduction

It's difficult to think about modern-day computing without the idea of random numbers. Random numbers are used in an array or varying computer disciplines such as games, simulations, randomized trials, even some randomized algorithms, and so on.

In this chapter, we aim to explore all the details of random numbers in PHP. Yes, that right — all of them.

In particular, we'll see what is a pseudo-random number in general, and the `rand()` and `mt_rand()` functions used to generate a new random number. We'll also explore the idea of manual seeding via the `srand()` and `mt_srand()` functions and finally how to obtain a random value in the range [0, 1) using `rand()` and a bit of arithmetic.

Let's begin.

## What are pseudo-random nmbers?

Random numbers generated by computers fall in two categories: pseudo-random numbers and cryptographically-secure random numbers.

Right now, we are concerned with pseudo-random numbers.

Let's start by defining what is it.

A pseudo-random number is a random number generated by a computer.

As the term implies, a 'pseudo-random' number is not truly random.

In particular, pseudo-random numbers generated by computers form a sequence whereby consecutive elements don't follow any pattern (i.e. they're random), however, there is a period to the whole sequence after which the entire sequence merely repeats.

In other words, pseudo-random numbers are random but predictable. And that's exactly why they're called pseudo-random.

An algorithm that generates a pseudo-random number is called a pseudo-random number generator, or a PRNG in short.

Almost all programming languages today provide PRNGs to obtain pseudo-random numbers easily. In all concerns but cryptography and other sophisticated areas, these ordinary PRNGs provide sufficient amounts of randomness.

These days, one of the most common PRNG algorithms used in almost all mainstream programming languages is the Mersenne Twister algorithm, invented by Makoto Matsumoto and Takuji Nishimura in 1997.

How exactly it works is beyond the scope of this course, but to summarize it, it's made in such a way so as to give a very good distribution of random numbers and keep the period sufficiently large.

Once again, remember that PRNGs don't generate truly random numbers and likewise should NOT be used in such sophisticated areas as cryptography.

The opposite of a pseudo-random number is a cryptographically-secure random number. Sometimes, it's also known as a cryptographically-secure pseudo-random number.

It's generated using even more complex math than used in an ordinary PRNG in order to yield a truly random sequence of numbers with an enormously huge period.

As the name suggests, such numbers are used in cryptography so that it's near impossible for any hacker to break into a system by any kind of a bruteforce approach.

## The `rand()` function

The `rand()` function is used to generate a random integer in PHP.

Here's its signature:

``````rand();
rand(\$min, \$max);``````

It can be called with no arguments at all, or with exactly two arguments.

If `rand()` is called without any arguments, a random integer between `0` and `getrandmax()` is returned.

The `getrandmax()` function returns the maximum random integer that could be returned by `rand()`. It's typically `-2147483647`.

On the other hand, if `rand()` is called with two arguments `\$min` and `\$max`, a random integer between those two integers (both inclusive) is returned.

First, let's experiment with the `rand()` function without any arguments:

``````<?php

echo rand(), "\n";
echo rand(), "\n";
echo rand(), "\n";``````
1195515822 1316549381 1929456481

The output in your case would obviously be different than this.

Now, let's experiment with the function as called with two integer arguments:

``````<?php

echo rand(1, 10), "\n";
echo rand(1, 10), "\n";
echo rand(1, 10), "\n";``````
1 10 3

Note that the random integer returned in this second case might be any of the provided integers to `rand()`, as is in our case in the first two outputs `1` and `10`. This is because they both are included in the range of the generated random number.

The first `\$min` argument to `rand()` could even be negative, as shown below:

``````<?php

echo rand(-50, 50), "\n";
echo rand(-50, 50), "\n";
echo rand(-50, 50), "\n";``````
25 -12 -8

Moving on, if the range of the desired number is greater than the range `0``getrandmax()`, then low-quality random numbers are returned. Low-quality means that the generated numbers won't be well-distributed, because certain numbers in such huge ranges can't ever be obtained.

This is simply a mathematical characteristic of scaling a random integer between `0` and `getrandmax()` to obtain an integer in the a given range.

To boil it down, always make sure that the range of the desired random integer is within the limits `0` and `getrandmax()`.

We are talking about the range of the random integer here, not the minimum and maximum possible. Hence, we can call something like `rand(-1 * getrandmax(), 0)` or even `rand(-2 * getrandmax(), -1 * getrandmax())`. In both of these cases, the minimum is clearly not `0`, but the range (i.e `\$max - \$min`) is within the range `getrandmax() - 0`.

## The `mt_rand()` function

If we explore a little into the documentation of PHP, we see another function called `mt_rand()` that also allows us to get a random number in the same range `0``getrandmax()`.

So then what's so special about `mt_rand()`? How does it differ from `rand()`?

Well, the reality is that by PHP 7.1.0, `rand()` and `mt_rand()` both generate a random number using the exact same implementation. In fact, as the documentation says, `rand()` is an alias of `mt_rand()`.

This behavior wasn't there in PHP since the very advent of `mt_rand()` into the standard collection of global functions. That is, `rand()` generated a random number using a different approach which was slow and not as high-quality as the Mersenne Twister PRNG function `mt_rand()`.

It was with PHP 7.1.0 that `rand()` was made to use `mt_rand()` internally.

Note, however, that `rand()` and `mt_rand()` aren't identical to one another as far as their operation is concerned. `rand()` allows the `\$max` argument to be less than `\$min` in order to preserve backwards compatibility with old PHP code. `mt_rand()` on the other hand, returns `false` in such a case.

Hence, from a usage perspective, there is really no difference between `rand()` and `mt_rand()`, given that we keep `\$max` greater than or equal to `\$min`.

There would be absolutely no difference if we use one or the other to generate a simple random number. Throughout this course, we'll use `rand()` instead of `mt_rand()` simply due to its short name.

Anyhow, now when you see `mt_rand()` in any code snippet out there, at least you'd know what it does.

## Seeding a PRNG

A pseudo-random number generator has to be fed a starting value in order to begin computation of a new random integer.

This initiation step is called seeding. The initial value supplied is likewise called the seed.

Back in the day, programmers in PHP had to manually seed the PRNG by calling `srand()` (or `mt_rand()`) and providing it a given value. However, this requirement is not necessary now — it's automatically done inside `rand()` (or `mt_rand()`) if seeding hasn't been performed previously.

But if we want to start with a particular seed, there's nothing wrong with manually calling `srand()`.

In the code below, we do exactly this:

``````<?php

srand(100)
echo rand();``````
1166953220

`srand(100)` seeds the PRNG used by PHP with the value `100`. This value is used to compute the first random number returned by `rand()` (or `mt_rand()`), which in this case is `1166953220`, after which every subsequent random integer is computed using the last value.

Calling `rand()` after `srand()` simply returns a random number based on the provided seed. If the seed is the same on multiple occasions, then the whole set of subsequent `rand()` calls would give the same set of random integers in both occasions as well.

In the code below, we demonstrate this idea:

``````<?php

srand(100);
echo rand(), "\n";
echo rand(), "\n";
echo rand(), "\n";

echo "\n";

srand(100);
echo rand(), "\n";
echo rand(), "\n";
echo rand(), "\n";``````
1166953220 1441295756 597793697 1166953220 1441295756 597793697

`srand(100)` is called twice followed by three calls to `rand()`. Notice the set of output generated by each of the two sets of statements here — they are both the same which confirms the fact that the same seed would always result in the same random sequence of integers.

As with `rand()` which is (almost) an alias of `mt_rand()`, the `srand()` function is an alias of `mt_srand()`. Call one or the other, it doesn't matter.

Now in almost all cases, we shouldn't be concerned with manually seeding the PRNG via `srand()` (or `mt_srand()`) unless and until we are extremely sure on what we are trying to achieve with a manual seed.

Ideally, seeding should be left to PHP to do all by itself, based on the timestamp at the time when the `rand()` call is made.

## Random float in the range [0, 1)

So given the `rand()` function, how do we go on to obtain a floating-point number in the range [0, 1) i.e. greater than or equal to 0 and less than 1?

Well, it's superbly easy.

What we need to do is simply divide the random number that we get by calling `rand()` by `getrandmax() + 1`.

The maximum random could be `getrandmax()`, so to get a number that's less than `1` we add `1` to `getrandmax()` before putting it in the denominator of the division.

In the code below, we create a simple function `random_float()` that returns a random float from the set [0, 1):

``````<?php

function random_float() {
return rand() / (getrandmax() + 1);
}

echo random_float(), "\n";
echo random_float(), "\n";
echo random_float(), "\n";
echo random_float(), "\n";
echo random_float(), "\n";``````
0.041215567849576 0.68517297459766 0.099202818237245 0.037415781989694 0.3945257011801

Superb.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage