{"id":13525961,"url":"https://github.com/ckknight/random-js","last_synced_at":"2025-05-15T07:07:35.191Z","repository":{"id":14197211,"uuid":"16903784","full_name":"ckknight/random-js","owner":"ckknight","description":"A mathematically correct random number generator library for JavaScript.","archived":false,"fork":false,"pushed_at":"2024-04-21T14:47:37.000Z","size":669,"stargazers_count":611,"open_issues_count":33,"forks_count":51,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-14T13:32:28.061Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ckknight.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-02-17T06:19:19.000Z","updated_at":"2025-05-12T06:48:50.000Z","dependencies_parsed_at":"2024-06-03T23:33:36.098Z","dependency_job_id":"cf83ab39-f786-416c-a808-2674929ddc22","html_url":"https://github.com/ckknight/random-js","commit_stats":{"total_commits":50,"total_committers":4,"mean_commits":12.5,"dds":"0.42000000000000004","last_synced_commit":"f000fd5c286bcf7c8a486940bb81deea19a99c55"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckknight%2Frandom-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckknight%2Frandom-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckknight%2Frandom-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckknight%2Frandom-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ckknight","download_url":"https://codeload.github.com/ckknight/random-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292043,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:23.861Z","updated_at":"2025-05-15T07:07:30.182Z","avatar_url":"https://github.com/ckknight.png","language":"TypeScript","readme":"# Random.js\n\n[![Build Status](https://travis-ci.org/ckknight/random-js.svg?branch=master)](https://travis-ci.org/ckknight/random-js)\n\nThis is designed to be a mathematically correct random number generator library for JavaScript.\n\nInspiration was primarily taken from C++11's `\u003crandom\u003e`.\n\n## Upgrading from 1.0\nUpgrading from 1.0 to 2.0 is a major, breaking change. For the most part, the way exports are defined is different. Instead of everything being available as static properties on a class-like function, random-js 2.0 exports each binding in accordance with current ECMAScript standards.\n\n## Why is this needed?\n\nDespite `Math.random()` being capable of producing numbers within [0, 1), there are a few downsides to doing so:\n\n- It is inconsistent between engines as to how many bits of randomness:\n  - Internet Explorer: 53 bits\n  - Mozilla Firefox: 53 bits\n  - Google Chrome/node.js: 32 bits\n  - Apple Safari: 32 bits\n- It is non-deterministic, which means you can't replay results consistently\n- In older browsers, there can be manipulation through cross-frame random polling. _This is mostly fixed in newer browsers and is required to be fixed in ECMAScript 6._\n\nAlso, and most crucially, most developers tend to use improper and biased logic as to generating integers within a uniform distribution.\n\n## How does Random.js alleviate these problems?\n\nRandom.js provides a set of \"engines\" for producing random integers, which consistently provide values within [0, 4294967295], i.e. 32 bits of randomness.\n\n- `nativeMath`: Utilizes [`Math.random()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) and converts its result to a signed integer. This is appropriate to use if you do not care for a deterministic implementation. Based on the implementation (which is hidden to you as a developer), the period may be shorter than expected and start repeating itself.\n- `browserCrypto`: Utilizes [`crypto.getRandomValues(Int32Array)`](https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues). Only supported on newer browsers, but promises cryptographically random numbers.\n- `nodeCrypto`: Utilizes [`require('crypto').randomBytes(size)`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback). Only supported on node.\n- `MersenneTwister19937`: An implementation of the [Mersenne Twister](http://en.wikipedia.org/wiki/Mersenne_twister) algorithm. Not cryptographically secure, but its results are repeatable. Must be seeded with a single integer or an array of integers or call `.autoSeed()` to automatically seed initial data. Guaranteed to produce consistent results across all JavaScript implementations assuming the same seed.\n\nOne is also free to implement their own engine as long as it returns 32-bit integers, either signed or unsigned.\n\nSome common, biased, _incorrect_ tool for generating random integers is as follows:\n\n    // DO NOT USE, BIASED LOGIC\n    function randomInt(min, max) {\n      return Math.floor(Math.random() * (max - min)) + min;\n    }\n    // DO NOT USE, BIASED LOGIC (typical C-like implementation)\n    function randomIntByModulo(min, max) {\n      var i = (Math.random() * 32768) \u003e\u003e\u003e 0;\n      return (i % (min - max)) + min;\n    }\n\nThe problem with both of these approaches is that the distribution of integers that it returns is not uniform. That is, it might be more biased to return `0` rather than `1`, making it inherently broken.\n\n`randomInt` may more evenly distribute its biased, but it is still wrong. `randomIntByModulo`, at least in the example given, is heavily biased to return [0, 67] over [68, 99].\n\nIn order to eliminate bias, sometimes the engine which random data is pulled from may need to be used more than once.\n\nRandom.js provides a series of distributions to alleviate this.\n\n## API\n\n### Engines\n\n- `nativeMath`: Utilizes `Math.random()`\n- `browserCrypto`: Utilizes `crypto.getRandomValues()`\n- `nodeCrypto`: Utilizes `require('crypto').randomBytes()`\n- `MersenneTwister19937`: Produces a new Mersenne Twister. Must be seeded before use.\n\nOr you can make your own!\n\n```ts\ninterface Engine {\n  next(): number; // an int32\n}\n```\n\nAny object that fulfills that interface is an `Engine`.\n\n### Mersenne Twister API\n\n- `const mt = MersenneTwister19937.seed(value)`: Seed the twister with an initial 32-bit integer.\n- `const mt = MersenneTwister19937.seedWithArray(array)`: Seed the twister with an array of 32-bit integers.\n- `const mt = MersenneTwister19937.autoSeed()`: Seed the twister with automatic information. This uses the current Date and other entropy sources.\n- `mt.next()`: Produce a 32-bit signed integer.\n- `mt.discard(count)`: Discard `count` random values. More efficient than running `mt.next()` repeatedly.\n- `mt.getUseCount()`: Return the number of times the engine has been used plus the number of discarded values.\n\nOne can seed a Mersenne Twister with the same value (`MersenneTwister19937.seed(value)`) or values (`MersenneTwister19937.seedWithArray(array)`) and discard the number of uses (`mt.getUseCount()`) to achieve the exact same state.\n\nIf you wish to know the initial seed of `MersenneTwister19937.autoSeed()`, it is recommended to use the `createEntropy()` function to create the seed manually (this is what `autoSeed` does under-the-hood).\n\n```js\nconst seed = createEntropy();\nconst mt = MersenneTwister19937.seedWithArray(seed);\nuseTwisterALot(mt); // you'll have to implement this yourself\nconst clone = MersenneTwister19937.seedWithArray(seed).discard(\n  mt.getUseCount()\n);\n// at this point, `mt` and `clone` will produce equivalent values\n```\n\n### Distributions\n\nRandom.js also provides a set of methods for producing useful data from an engine.\n\n- `integer(min, max)(engine)`: Produce an integer within the inclusive range [`min`, `max`]. `min` can be at its minimum -9007199254740992 (-2 ** 53). `max` can be at its maximum 9007199254740992 (2 ** 53).\n- `real(min, max, inclusive)(engine)`: Produce a floating point number within the range [`min`, `max`) or [`min`, `max`]. Uses 53 bits of randomness.\n- `bool()(engine)`: Produce a boolean with a 50% chance of it being `true`.\n- `bool(percentage)(engine)`: Produce a boolean with the specified chance causing it to be `true`.\n- `bool(numerator, denominator)(engine)`: Produce a boolean with `numerator`/`denominator` chance of it being true.\n- `pick(engine, array[, begin[, end]])`: Return a random value within the provided `array` within the sliced bounds of `begin` and `end`.\n- `picker(array[, begin[, end]])(engine)`: Same as `pick(engine, array, begin, end)`.\n- `shuffle(engine, array)`: Shuffle the provided `array` (in-place). Similar to `.sort()`.\n- `sample(engine, population, sampleSize)`: From the `population` array, produce an array with `sampleSize` elements that are randomly chosen without repeats.\n- `die(sideCount)(engine)`: Same as `integer(1, sideCount)(engine)`\n- `dice(sideCount, dieCount)(engine)`: Produce an array of length `dieCount` with as many `die` rolls.\n- `uuid4(engine)`: Produce a [Universally Unique Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier) Version 4.\n- `string()(engine, length)`: Produce a random string using numbers, uppercase and lowercase letters, `_`, and `-` of length `length`.\n- `string(pool)(engine, length)`: Produce a random string using the provided string `pool` as the possible characters to choose from of length `length`.\n- `hex()(engine, length)` or `hex(false)(engine, length)`: Produce a random string comprised of numbers or the characters `abcdef` of length `length`.\n- `hex(true)(engine, length)`: Produce a random string comprised of numbers or the characters `ABCDEF` of length `length`.\n- `date(start, end)(engine)`: Produce a random `Date` within the inclusive range of [`start`, `end`]. `start` and `end` must both be `Date`s.\n\nAn example of using `integer` would be as such:\n\n```js\n// create a Mersenne Twister-19937 that is auto-seeded based on time and other random values\nconst engine = MersenneTwister19937.autoSeed();\n// create a distribution that will consistently produce integers within inclusive range [0, 99].\nconst distribution = integer(0, 99);\n// generate a number that is guaranteed to be within [0, 99] without any particular bias.\nfunction generateNaturalLessThan100() {\n  return distribution(engine);\n}\n```\n\nProducing a distribution should be considered a cheap operation, but producing a new Mersenne Twister can be expensive.\n\nAn example of producing a random SHA1 hash:\n\n```js\n// using essentially Math.random()\nvar engine = nativeMath;\n// lower-case Hex string distribution\nvar distribution = hex(false);\n// generate a 40-character hex string\nfunction generateSHA1() {\n  return distribution(engine, 40);\n}\n```\n\n## Alternate API\n\nThere is an alternate API which may be easier to use, but may be less performant. In scenarios where performance is paramount, it is recommended to use the aforementioned API.\n\n```js\nconst random = new Random(\n  MersenneTwister19937.seedWithArray([0x12345678, 0x90abcdef])\n);\nconst value = r.integer(0, 99);\n\nconst otherRandom = new Random(); // same as new Random(nativeMath)\n```\n\nThis abstracts the concepts of engines and distributions.\n\n- `r.integer(min, max)`: Produce an integer within the inclusive range [`min`, `max`]. `min` can be at its minimum -9007199254740992 (2 ** 53). `max` can be at its maximum 9007199254740992 (2 ** 53). The special number `-0` is never returned.\n- `r.real(min, max, inclusive)`: Produce a floating point number within the range [`min`, `max`) or [`min`, `max`]. Uses 53 bits of randomness.\n- `r.bool()`: Produce a boolean with a 50% chance of it being `true`.\n- `r.bool(percentage)`: Produce a boolean with the specified chance causing it to be `true`.\n- `r.bool(numerator, denominator)`: Produce a boolean with `numerator`/`denominator` chance of it being true.\n- `r.pick(array[, begin[, end]])`: Return a random value within the provided `array` within the sliced bounds of `begin` and `end`.\n- `r.shuffle(array)`: Shuffle the provided `array` (in-place). Similar to `.sort()`.\n- `r.sample(population, sampleSize)`: From the `population` array, produce an array with `sampleSize` elements that are randomly chosen without repeats.\n- `r.die(sideCount)`: Same as `r.integer(1, sideCount)`\n- `r.dice(sideCount, dieCount)`: Produce an array of length `dieCount` with as many `die` rolls.\n- `r.uuid4()`: Produce a [Universally Unique Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier) Version 4.\n- `r.string(length)`: Produce a random string using numbers, uppercase and lowercase letters, `_`, and `-` of length `length`.\n- `r.string(length, pool)`: Produce a random string using the provided string `pool` as the possible characters to choose from of length `length`.\n- `r.hex(length)` or `r.hex(length, false)`: Produce a random string comprised of numbers or the characters `abcdef` of length `length`.\n- `r.hex(length, true)`: Produce a random string comprised of numbers or the characters `ABCDEF` of length `length`.\n- `r.date(start, end)`: Produce a random `Date` within the inclusive range of [`start`, `end`]. `start` and `end` must both be `Date`s.\n\n## Usage\n\n### node.js\n\nIn your project, run the following command:\n\n```sh\nnpm install random-js\n```\n\nor\n\n```sh\nyarn add random-js\n```\n\nIn your code:\n\n```js\n// ES6 Modules\nimport { Random } from \"random-js\";\nconst random = new Random(); // uses the nativeMath engine\nconst value = random.integer(1, 100);\n```\n\n```js\n// CommonJS Modules\nconst { Random } = require(\"random-js\");\nconst random = new Random(); // uses the nativeMath engine\nconst value = random.integer(1, 100);\n```\n\nOr to have more control:\n\n```js\nconst Random = require(\"random-js\").Random;\nconst random = new Random(MersenneTwister19937.autoSeed());\nconst value = random.integer(1, 100);\n```\n\nIt is recommended to create one shared engine and/or `Random` instance per-process rather than one per file.\n\n### Browser using AMD or RequireJS\n\nDownload `random.min.js` and place it in your project, then use one of the following patterns:\n\n```js\ndefine(function(require) {\n  var Random = require(\"random\");\n  return new Random.Random(Random.MersenneTwister19937.autoSeed());\n});\n\ndefine(function(require) {\n  var Random = require(\"random\");\n  return new Random.Random();\n});\n\ndefine([\"random\"], function(Random) {\n  return new Random.Random(Random.MersenneTwister19937.autoSeed());\n});\n```\n\n### Browser using `\u003cscript\u003e` tag\n\nDownload `random-js.min.js` and place it in your project, then add it as a `\u003cscript\u003e` tag as such:\n\n```html\n\u003cscript src=\"lib/random-js.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  // Random is now available as a global (on the window object)\n  var random = new Random.Random();\n  alert(\"Random value from 1 to 100: \" + random.integer(1, 100));\n\u003c/script\u003e\n```\n\n## Extending\n\nYou can add your own methods to `Random` instances, as such:\n\n```js\nvar random = new Random();\nrandom.bark = function() {\n  if (this.bool()) {\n    return \"arf!\";\n  } else {\n    return \"woof!\";\n  }\n};\nrandom.bark(); //=\u003e \"arf!\" or \"woof!\"\n```\n\nThis is the recommended approach, especially if you only use one instance of `Random`.\n\nOr you could even make your own subclass of Random:\n\n```js\nfunction MyRandom(engine) {\n  return Random.call(this, engine);\n}\nMyRandom.prototype = Object.create(Random.prototype);\nMyRandom.prototype.constructor = MyRandom;\nMyRandom.prototype.mood = function() {\n  switch (this.integer(0, 2)) {\n    case 0:\n      return \"Happy\";\n    case 1:\n      return \"Content\";\n    case 2:\n      return \"Sad\";\n  }\n};\nvar random = new MyRandom();\nrandom.mood(); //=\u003e \"Happy\", \"Content\", or \"Sad\"\n```\n\nOr, if you have a build tool are are in an ES6+ environment:\n\n```js\nclass MyRandom extends Random {\n  mood() {\n    switch (this.integer(0, 2)) {\n      case 0:\n        return \"Happy\";\n      case 1:\n        return \"Content\";\n      case 2:\n        return \"Sad\";\n    }\n  }\n}\nconst random = new MyRandom();\nrandom.mood(); //=\u003e \"Happy\", \"Content\", or \"Sad\"\n```\n\n## Testing\n\nAll the code in Random.js is fully tested and covered using `jest`.\n\nTo run tests in node.js:\n\n```sh\nnpm install\nnpm test\n```\n\nor\n\n```sh\nyarn install\nyarn test\n```\n\n## License\n\nThe MIT License (MIT).\n\nSee the LICENSE file in this project for more details.\n","funding_links":[],"categories":["Repository","TypeScript","Math"],"sub_categories":["Number"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckknight%2Frandom-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fckknight%2Frandom-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckknight%2Frandom-js/lists"}