How Lodash _.random Implements Pseudo-Randomness

The Lodash library provides the _.random utility to streamline the generation of random integers and floating-point numbers within user-defined ranges. Contrary to what some developers assume, Lodash does not implement a custom pseudo-random number generator (PRNG) algorithm from scratch. Instead, it serves as a mathematical and ergonomic wrapper around the JavaScript runtime's native Math.random() engine, providing bound validation, flexible argument handling, and distribution scaling.

Delegation to Native Math.random()

At its core, Lodash's _.random delegates the actual generation of entropy to the host environment via Math.random(). In modern JavaScript runtimes such as Node.js and Google Chrome (V8), Mozilla Firefox (SpiderMonkey), and Safari (JavaScriptCore), Math.random() is typically implemented using the xorshift128+ PRNG algorithm. Because Lodash relies entirely on this native API, _.random inherits all performance characteristics, distribution properties, and deterministic limitations of the underlying engine. Consequently, the function produces pseudo-random results that are suitable for general application logic, games, or simulations, but are not cryptographically secure.

Argument Normalization and Boundary Handling

Before generating a value, _.random standardizes the arguments passed to it:

  1. Parameter Shifting: If only one argument is supplied, Lodash treats 0 as the lower bound and the provided argument as the upper bound.
  2. Boundary Swapping: If the specified lower bound is greater than the upper bound, Lodash automatically swaps the values to prevent negative range calculations.
  3. Float Detection: Lodash inspects both arguments and the optional floating boolean flag. If either argument is a floating-point number or if the third argument is explicitly set to true, the function switches from integer mode to floating-point mode.

The Scaling Algorithms

Once boundaries and types are resolved, Lodash applies arithmetic formulas to scale the [0, 1) output of Math.random() to the target interval.

1. Integer Generation

When returning integers, Lodash delivers an inclusive range [lower, upper]. The standard implementation scales the range by the difference between the bounds plus one, then truncates the result using Math.floor:

lower + Math.floor(Math.random() * (upper - lower + 1))

Adding 1 ensures that the upper limit has an equal probability of being reached after flooring.

2. Floating-Point Generation

When returning floating-point values, Lodash avoids inclusive rounding to maintain standard float distribution across the range [lower, upper). It calculates the value by directly multiplying the native output by the span of the bounds:

lower + (Math.random() * (upper - lower))

Lodash also includes precision safeguards to ensure that numerical limits defined by JavaScript's 64-bit binary floating-point standard (Number.MAX_SAFE_INTEGER and small decimal fractions) do not produce unexpected rounding errors at the edge of the range.

Cryptographic Considerations

Because _.random abstracts Math.random() rather than the Web Cryptography API (crypto.getRandomValues()), its internal state can theoretically be inferred after observing a sequence of outputs. Developers requiring unpredictability for tokens, keys, passwords, or security mechanisms should avoid _.random and use cryptographic alternatives instead.