A more complete random API?

Right now, in Javascript, our main source of randomness comes from a single function: Math.random(). I'm wondering if there would be interest in adding a more full-blown random library to Javascript, and if so, what kinds of random methods should exist in this library?

Some requirements:

  • It should provide easy-to-use methods for common random needs (i.e. provide a Random.randInt(start, end) instead of having people use common and incorrect patterns we see everywhere today, such as Math.floor(Math.random() * (end - start)) + start. It's also important to provide proper implementation of random logic that's difficult to implement correctly by hand, like Random.shuffle(array).
  • It should be seed-able. i.e. something like const myRandGen = new Random(<seed>); myRandGen.randInt(start, end)

Just to get things started, here's a handful of methods that a new Random API could include:

Random.randInt(2, 5) // Either returns 2, 3, or 4
Random.randBigInt(2n, 5n)
Random.randBool() // Either true or false
Random.randFloat(start, end) // A float where start <= x < end

Random.choice(['a', 'b', 'c']) // Reteurns a random entry from the array
Random.choice('abc') // Returns a random character
const newArray = Random.shuffle(['a', 'b', 'c'])
Random.shuffleInPlace(myArray)

const gen = new Random(<optional seed>)
gen.randInt(...) // The instance constaints all of the static methods.
const newGen = gen.clone() // Clones the pseudo-random-number generator at its current state
console.assert(gen.randBool() === newGen.randBool())

We could also provide methods to provide random values using other distributions besides a linear one. It's probably wise not to stick every possible random-related thing into this, anyone who's wanting to do deep statistical logic, or to build some game that deeply depends on random generation should probably install a more full-featured random library. The build-in API should just try and cover the most common use-cases, so people don't have to keep twiddling with floats from Math.random() to do everyday tasks.


A note on Random.shuffle()

Random.shuffle() (and Random.choice()) has been discussed previously on this form here. Over there, @claudiameadows brought up an interesting point that I was unaware of.

Shuffling's way harder than you'd think to do right - the gold standard for it requires enough bits of RNG state to hold all possible mutations in order to hit all permutations and for all but small arrays (of <= 34 entries), they can't even use what they use for Math.random().
...
And yes, I'm saying that Python's default is actually very bad.

I think this is an argument for why the Javascript language needs a random shuffle method. Any home-grown one is likely to be implemented worse than what we can do natively in Javascript. And yes, maybe Javascript can't provide a truly random shuffle method, but we can reflect this shortcoming in the method name, so it's clear to users that the shuffle method is not perfect. For example, Random.semiRandomShuffle(array). How to actually name it can be debated, but providing a proper shuffle method with a name that indicates its shortcomings is better than not having one at all.


prior art:

4 Likes

Exactly!

Existing proposal for seeded random

1 Like

That looks very related. It unfortunately only provides seeded random number generation, not helper functions such as randInt(), which was my bigger interest here. Maybe it'll be better to move this discussion onto that proposal and see if they're willing to expand the proposal.

Actually, as I've looked closer at that proposal, I don't really see a feasible way of trying to move this conversation there. The idea of a fuller random library seems to be completely out of the scope of that proposal and would need to be a proposal of its own, that happens to have some overlapping feature.

But, they do have some good thoughts going on there. Like, the idea of having all implementations use the same pseudo-random-number-generator, so that you can use the same seed on any JavaScript platform and receive the same results.

1 Like

Note: the Mersenne Twister fails numerous statistical tests for randomness. It's only used because of the massive state size

I would find a randomRange implementation really useful as it would eliminate having to calculate rounding vs truncating values all the time and would also make it specific as to what was being requested.

Something like Math.randomRange(low=0, high=100, step=1)

1 Like