GithubHelp home page GithubHelp logo

ckknight / random-js Goto Github PK

View Code? Open in Web Editor NEW
601.0 11.0 48.0 669 KB

A mathematically correct random number generator library for JavaScript.

License: MIT License

JavaScript 5.23% TypeScript 94.77%

random-js's Introduction

Random.js

Build Status

This is designed to be a mathematically correct random number generator library for JavaScript.

Inspiration was primarily taken from C++11's <random>.

Upgrading from 1.0

Upgrading 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.

Why is this needed?

Despite Math.random() being capable of producing numbers within [0, 1), there are a few downsides to doing so:

  • It is inconsistent between engines as to how many bits of randomness:
    • Internet Explorer: 53 bits
    • Mozilla Firefox: 53 bits
    • Google Chrome/node.js: 32 bits
    • Apple Safari: 32 bits
  • It is non-deterministic, which means you can't replay results consistently
  • 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.

Also, and most crucially, most developers tend to use improper and biased logic as to generating integers within a uniform distribution.

How does Random.js alleviate these problems?

Random.js provides a set of "engines" for producing random integers, which consistently provide values within [0, 4294967295], i.e. 32 bits of randomness.

  • nativeMath: Utilizes 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.
  • browserCrypto: Utilizes crypto.getRandomValues(Int32Array). Only supported on newer browsers, but promises cryptographically random numbers.
  • nodeCrypto: Utilizes require('crypto').randomBytes(size). Only supported on node.
  • MersenneTwister19937: An implementation of the 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.

One is also free to implement their own engine as long as it returns 32-bit integers, either signed or unsigned.

Some common, biased, incorrect tool for generating random integers is as follows:

// DO NOT USE, BIASED LOGIC
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
// DO NOT USE, BIASED LOGIC (typical C-like implementation)
function randomIntByModulo(min, max) {
  var i = (Math.random() * 32768) >>> 0;
  return (i % (min - max)) + min;
}

The 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.

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].

In order to eliminate bias, sometimes the engine which random data is pulled from may need to be used more than once.

Random.js provides a series of distributions to alleviate this.

API

Engines

  • nativeMath: Utilizes Math.random()
  • browserCrypto: Utilizes crypto.getRandomValues()
  • nodeCrypto: Utilizes require('crypto').randomBytes()
  • MersenneTwister19937: Produces a new Mersenne Twister. Must be seeded before use.

Or you can make your own!

interface Engine {
  next(): number; // an int32
}

Any object that fulfills that interface is an Engine.

Mersenne Twister API

  • const mt = MersenneTwister19937.seed(value): Seed the twister with an initial 32-bit integer.
  • const mt = MersenneTwister19937.seedWithArray(array): Seed the twister with an array of 32-bit integers.
  • const mt = MersenneTwister19937.autoSeed(): Seed the twister with automatic information. This uses the current Date and other entropy sources.
  • mt.next(): Produce a 32-bit signed integer.
  • mt.discard(count): Discard count random values. More efficient than running mt.next() repeatedly.
  • mt.getUseCount(): Return the number of times the engine has been used plus the number of discarded values.

One 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.

If 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).

const seed = createEntropy();
const mt = MersenneTwister19937.seedWithArray(seed);
useTwisterALot(mt); // you'll have to implement this yourself
const clone = MersenneTwister19937.seedWithArray(seed).discard(
  mt.getUseCount()
);
// at this point, `mt` and `clone` will produce equivalent values

Distributions

Random.js also provides a set of methods for producing useful data from an engine.

  • 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).
  • real(min, max, inclusive)(engine): Produce a floating point number within the range [min, max) or [min, max]. Uses 53 bits of randomness.
  • bool()(engine): Produce a boolean with a 50% chance of it being true.
  • bool(percentage)(engine): Produce a boolean with the specified chance causing it to be true.
  • bool(numerator, denominator)(engine): Produce a boolean with numerator/denominator chance of it being true.
  • pick(engine, array[, begin[, end]]): Return a random value within the provided array within the sliced bounds of begin and end.
  • picker(array[, begin[, end]])(engine): Same as pick(engine, array, begin, end).
  • shuffle(engine, array): Shuffle the provided array (in-place). Similar to .sort().
  • sample(engine, population, sampleSize): From the population array, produce an array with sampleSize elements that are randomly chosen without repeats.
  • die(sideCount)(engine): Same as integer(1, sideCount)(engine)
  • dice(sideCount, dieCount)(engine): Produce an array of length dieCount with as many die rolls.
  • uuid4(engine): Produce a Universally Unique Identifier Version 4.
  • string()(engine, length): Produce a random string using numbers, uppercase and lowercase letters, _, and - of length length.
  • string(pool)(engine, length): Produce a random string using the provided string pool as the possible characters to choose from of length length.
  • hex()(engine, length) or hex(false)(engine, length): Produce a random string comprised of numbers or the characters abcdef of length length.
  • hex(true)(engine, length): Produce a random string comprised of numbers or the characters ABCDEF of length length.
  • date(start, end)(engine): Produce a random Date within the inclusive range of [start, end]. start and end must both be Dates.

An example of using integer would be as such:

// create a Mersenne Twister-19937 that is auto-seeded based on time and other random values
const engine = MersenneTwister19937.autoSeed();
// create a distribution that will consistently produce integers within inclusive range [0, 99].
const distribution = integer(0, 99);
// generate a number that is guaranteed to be within [0, 99] without any particular bias.
function generateNaturalLessThan100() {
  return distribution(engine);
}

Producing a distribution should be considered a cheap operation, but producing a new Mersenne Twister can be expensive.

An example of producing a random SHA1 hash:

// using essentially Math.random()
var engine = nativeMath;
// lower-case Hex string distribution
var distribution = hex(false);
// generate a 40-character hex string
function generateSHA1() {
  return distribution(engine, 40);
}

Alternate API

There 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.

const random = new Random(
  MersenneTwister19937.seedWithArray([0x12345678, 0x90abcdef])
);
const value = r.integer(0, 99);

const otherRandom = new Random(); // same as new Random(nativeMath)

This abstracts the concepts of engines and distributions.

  • 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.
  • r.real(min, max, inclusive): Produce a floating point number within the range [min, max) or [min, max]. Uses 53 bits of randomness.
  • r.bool(): Produce a boolean with a 50% chance of it being true.
  • r.bool(percentage): Produce a boolean with the specified chance causing it to be true.
  • r.bool(numerator, denominator): Produce a boolean with numerator/denominator chance of it being true.
  • r.pick(array[, begin[, end]]): Return a random value within the provided array within the sliced bounds of begin and end.
  • r.shuffle(array): Shuffle the provided array (in-place). Similar to .sort().
  • r.sample(population, sampleSize): From the population array, produce an array with sampleSize elements that are randomly chosen without repeats.
  • r.die(sideCount): Same as r.integer(1, sideCount)
  • r.dice(sideCount, dieCount): Produce an array of length dieCount with as many die rolls.
  • r.uuid4(): Produce a Universally Unique Identifier Version 4.
  • r.string(length): Produce a random string using numbers, uppercase and lowercase letters, _, and - of length length.
  • r.string(length, pool): Produce a random string using the provided string pool as the possible characters to choose from of length length.
  • r.hex(length) or r.hex(length, false): Produce a random string comprised of numbers or the characters abcdef of length length.
  • r.hex(length, true): Produce a random string comprised of numbers or the characters ABCDEF of length length.
  • r.date(start, end): Produce a random Date within the inclusive range of [start, end]. start and end must both be Dates.

Usage

node.js

In your project, run the following command:

npm install random-js

or

yarn add random-js

In your code:

// ES6 Modules
import { Random } from "random-js";
const random = new Random(); // uses the nativeMath engine
const value = random.integer(1, 100);
// CommonJS Modules
const { Random } = require("random-js");
const random = new Random(); // uses the nativeMath engine
const value = random.integer(1, 100);

Or to have more control:

const Random = require("random-js").Random;
const random = new Random(MersenneTwister19937.autoSeed());
const value = random.integer(1, 100);

It is recommended to create one shared engine and/or Random instance per-process rather than one per file.

Browser using AMD or RequireJS

Download random.min.js and place it in your project, then use one of the following patterns:

define(function(require) {
  var Random = require("random");
  return new Random.Random(Random.MersenneTwister19937.autoSeed());
});

define(function(require) {
  var Random = require("random");
  return new Random.Random();
});

define(["random"], function(Random) {
  return new Random.Random(Random.MersenneTwister19937.autoSeed());
});

Browser using <script> tag

Download random-js.min.js and place it in your project, then add it as a <script> tag as such:

<script src="lib/random-js.min.js"></script>
<script>
  // Random is now available as a global (on the window object)
  var random = new Random.Random();
  alert("Random value from 1 to 100: " + random.integer(1, 100));
</script>

Extending

You can add your own methods to Random instances, as such:

var random = new Random();
random.bark = function() {
  if (this.bool()) {
    return "arf!";
  } else {
    return "woof!";
  }
};
random.bark(); //=> "arf!" or "woof!"

This is the recommended approach, especially if you only use one instance of Random.

Or you could even make your own subclass of Random:

function MyRandom(engine) {
  return Random.call(this, engine);
}
MyRandom.prototype = Object.create(Random.prototype);
MyRandom.prototype.constructor = MyRandom;
MyRandom.prototype.mood = function() {
  switch (this.integer(0, 2)) {
    case 0:
      return "Happy";
    case 1:
      return "Content";
    case 2:
      return "Sad";
  }
};
var random = new MyRandom();
random.mood(); //=> "Happy", "Content", or "Sad"

Or, if you have a build tool are are in an ES6+ environment:

class MyRandom extends Random {
  mood() {
    switch (this.integer(0, 2)) {
      case 0:
        return "Happy";
      case 1:
        return "Content";
      case 2:
        return "Sad";
    }
  }
}
const random = new MyRandom();
random.mood(); //=> "Happy", "Content", or "Sad"

Testing

All the code in Random.js is fully tested and covered using jest.

To run tests in node.js:

npm install
npm test

or

yarn install
yarn test

License

The MIT License (MIT).

See the LICENSE file in this project for more details.

random-js's People

Contributors

ckknight avatar pariser avatar ssoloff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

random-js's Issues

2.0.0-rc2 doesn't build with webpack/babel

Been using random-js with webpack/babel without problems for a while but the new version is causing errors in babel for me

ERROR in ./node_modules/random-js/dist/random-js.mjs
    Module parse failed: Unexpected token (459:10)
    You may need an appropriate loader to handle this file type.
    |         }
    |     }
    |     catch {
    |         // nothing to do here
    |     }
     @ ./js/controller.js 9:16-36
     @ ./js/main.js

Switching back an older version fixes it for me.

So far I've just imported it and new'd it up, otherwise haven't done much else

import { Random } from "random-js";

const random = new Random();

// other, non random related code?

The config part of my webpack.config.js file looks like

{
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                query: {
                    presets: ['env']
                }
            }
        ]
    },
    stats: {
        colors: true
    },
    entry: './js/main.js',
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'main.bundle.js'
    },
    devtool: 'source-map'
}

Let me know if you need any more info!

discard doesn't work

Expected: different values printed each time
What happened: same value printed each time

var Random = require("random-js");
for (var i = 0; i < 10; i++) {
  var mt = Random.engines.mt19937().seed(1337).discard(i); 
  console.log(i, mt());
}

Output:

0 1125387415
1 1125387415
2 1125387415
3 1125387415
4 1125387415
5 1125387415
6 1125387415
7 1125387415
8 1125387415
9 1125387415

nativeMath returns signed integers

The README states:

nativeMath: Utilizes Math.random() and converts its result to an unsigned integer.

but looking at the code it looks like it will be a signed integer that is returned, as the only bitwise operator that ensures a zero sign bit is >>>.

nativeMath: function () {
  return (Math.random() * 0x100000000) | 0;
},

A quick test confirms it:

var Random = require("random-js");
console.log( Random.engines.nativeMath() );
// -2121263325

Question: replicating exact functionality of Math.random()

Kind of 2 quick questions:

  1. I want to replicate the exact output of Math.random(), is this correct? real(0, 1, false)(engine);
  2. I'm replacing Math.random() with the above because I want the output to be unpredictable, as I've seen that its possible, given a sample of outputs of Math.random(), a user can determine what the next outputs will be. I was wondering if you could confirm, for my sanity, that using this library will prevent that? I'm using nodeCrypto as an engine.

More information about randomInt being biased?

I looked sideways at your readme when you said that:

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

produced a biased/non-uniform distribution. Math.random()'s contract is to produce a random number from a uniform distribution on [0, 1), and given that contract, I don't see how randomInt incorrectly transforms that to a uniform distribution of the integers in [min, max). It's a bit unclear whether you're suggesting that Math.random() fails to be uniformly distributed on [0, 1). Are you suggesting that? If so, which browsers are affected?

I tried this on Chrome 45:

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

var tallies = [0, 0, 0, 0, 0];

for (var i = 0; i !== 1000000; i++) {
  tallies[randomInt(0, 5)]++;
}

console.log(tallies);

And got this output:

[199601, 200204, 200379, 200016, 199800]

So it at least appears to be right. Could you elaborate please?

Random.sample() results are biased

Thanks for making a nice library. I was looking for a seed-able PRNG and random-js fits the bill.
I was using Random.sample(population, 1) and noticed that it always returns the same result, namely the last item in the population array.
Here is test code:

var Random = require('./random.js');
var r = new Random(Random.engines.mt19937().autoSeed());
var hits = {};
var population = ['a', 'b', 'c', 'd', 'e'];
var sampleSize = 1;
for(var i = 0; i < 100000; i++) {
  var k = r.sample(population, sampleSize).join(',');
  hits[k]++ || (hits[k] = 1); 
}
console.log(hits);

When I run it with node, it prints out the following:
{ e: 100000 }

When I use sampleSize = 2, the results also seem to heavily favor one of the elements of the population array:
{ 'd,b': 20013,
'd,c': 19884,
'd,e': 20011,
'd,a': 20069,
'e,d': 20023 }

This smells like an off-by-one somewhere... Or am I missing something?

Thanks.

  • Peter

install issue with node v0.12.6

▶ npm install --save random-js

npm WARN package.json [email protected] No repository field.
-
> [email protected] install /Users/tim/oakleon/isotope/node_modules/random-js/node_modules/microtime
> node-gyp rebuild

  CXX(target) Release/obj.target/microtime/src/microtime.o
In file included from ../src/microtime.cc:11:
../node_modules/nan/nan.h:318:13: error: no member named 'New' in 'v8::String'
    return  _NAN_ERROR(v8::Exception::Error, errmsg);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:322:5: error: no member named 'ThrowException' in namespace 'v8'
    _NAN_THROW_ERROR(v8::Exception::Error, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:11: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
      ~~~~^
../node_modules/nan/nan.h:322:5: error: no member named 'New' in 'v8::String'
    _NAN_THROW_ERROR(v8::Exception::Error, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:26: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
                         ^~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:327:9: error: no type named 'ThrowException' in namespace 'v8'
    v8::ThrowException(error);
    ~~~~^
../node_modules/nan/nan.h:334:65: error: no member named 'New' in 'v8::String'
    v8::Local<v8::Value> err = v8::Exception::Error(v8::String::New(msg));
                                                    ~~~~~~~~~~~~^
../node_modules/nan/nan.h:336:26: error: no member named 'New' in 'v8::String'
    obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber));
             ~~~~~~~~~~~~^
../node_modules/nan/nan.h:336:65: error: too few arguments to function call, expected 2, have 1
    obj->Set(v8::String::New("code"), v8::Int32::New(errorNumber));
                                      ~~~~~~~~~~~~~~            ^
/Users/tim/.node-gyp/0.12.6/deps/v8/include/v8.h:2012:3: note: 'New' declared here
  static Local<Integer> New(Isolate* isolate, int32_t value);
  ^
In file included from ../src/microtime.cc:11:
../node_modules/nan/nan.h:348:12: error: no member named 'New' in 'v8::String'
    return _NAN_ERROR(v8::Exception::TypeError, errmsg);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:352:5: error: no member named 'ThrowException' in namespace 'v8'
    _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:11: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
      ~~~~^
../node_modules/nan/nan.h:352:5: error: no member named 'New' in 'v8::String'
    _NAN_THROW_ERROR(v8::Exception::TypeError, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:26: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
                         ^~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:356:12: error: no member named 'New' in 'v8::String'
    return _NAN_ERROR(v8::Exception::RangeError, errmsg);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:360:5: error: no member named 'ThrowException' in namespace 'v8'
    _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:11: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
      ~~~~^
../node_modules/nan/nan.h:360:5: error: no member named 'New' in 'v8::String'
    _NAN_THROW_ERROR(v8::Exception::RangeError, errmsg);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:303:26: note: expanded from macro '_NAN_THROW_ERROR'
      v8::ThrowException(_NAN_ERROR(fun, errmsg));                             \
                         ^~~~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:298:50: note: expanded from macro '_NAN_ERROR'
# define _NAN_ERROR(fun, errmsg) fun(v8::String::New(errmsg))
                                     ~~~~~~~~~~~~^
../node_modules/nan/nan.h:668:49: error: too few arguments to function call, single argument 'isolate' was not specified
    v8::Local<v8::Object> obj = v8::Object::New();
                                ~~~~~~~~~~~~~~~ ^
/Users/tim/.node-gyp/0.12.6/deps/v8/include/v8.h:2388:3: note: 'New' declared here
  static Local<Object> New(Isolate* isolate);
  ^
In file included from ../src/microtime.cc:11:
../node_modules/nan/nan.h:669:14: error: no member named 'NewSymbol' in 'v8::String'; did you mean 'IsSymbol'?
    obj->Set(NanSymbol("callback"), fn);
             ^~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:159:38: note: expanded from macro 'NanSymbol'
#define NanSymbol(value) v8::String::NewSymbol(value)
                         ~~~~~~~~~~~~^
/Users/tim/.node-gyp/0.12.6/deps/v8/include/v8.h:1379:8: note: 'IsSymbol' declared here
  bool IsSymbol() const;
       ^
In file included from ../src/microtime.cc:11:
../node_modules/nan/nan.h:669:14: error: call to non-static member function without an object argument
    obj->Set(NanSymbol("callback"), fn);
             ^~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:159:38: note: expanded from macro 'NanSymbol'
#define NanSymbol(value) v8::String::NewSymbol(value)
                         ~~~~~~~~~~~~^~~~~~~~~
../node_modules/nan/nan.h:675:12: error: no member named 'Dispose' in 'v8::Persistent<v8::Object,
      v8::NonCopyablePersistentTraits<v8::Object> >'
    handle.Dispose();
    ~~~~~~ ^
../node_modules/nan/nan.h:676:12: error: no member named 'Clear' in 'v8::Persistent<v8::Object, v8::NonCopyablePersistentTraits<v8::Object>
      >'
    handle.Clear();
    ~~~~~~ ^
../node_modules/nan/nan.h:680:46: error: no member named 'NewSymbol' in 'v8::String'; did you mean 'IsSymbol'?
    return NanPersistentToLocal(handle)->Get(NanSymbol("callback"))
                                             ^~~~~~~~~~~~~~~~~~~~~
../node_modules/nan/nan.h:159:38: note: expanded from macro 'NanSymbol'
#define NanSymbol(value) v8::String::NewSymbol(value)
                         ~~~~~~~~~~~~^
/Users/tim/.node-gyp/0.12.6/deps/v8/include/v8.h:1379:8: note: 'IsSymbol' declared here
  bool IsSymbol() const;
       ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
make: *** [Release/obj.target/microtime/src/microtime.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/Users/tim/.nvm/versions/node/v0.12.6/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:269:23)
gyp ERR! stack     at ChildProcess.emit (events.js:110:17)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (child_process.js:1074:12)
gyp ERR! System Darwin 14.4.0
gyp ERR! command "node" "/Users/tim/.nvm/versions/node/v0.12.6/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/tim/oakleon/isotope/node_modules/random-js/node_modules/microtime
gyp ERR! node -v v0.12.6
gyp ERR! node-gyp -v v2.0.1
gyp ERR! not ok
npm WARN optional dep failed, continuing [email protected]
[email protected] node_modules/random-js
└── [email protected]

Need to push 1.0.5 up to NPM servers!

Hey guys,

I have been struggling with the the sample function. Turns out, when I run the following code:

var random = require('random-js')(require('random-js').engines.nativeMath);
for(var n = 0; n < 100; n += 1)
{
console.log(random.sample([1,2,3,4,5], 1));
}

I will always get 5 in the output. As it turns out, you have already fixed it:

#7

But this fix has not been sent up to NPM! The latest copy on the NPM servers has the old code which still has this flaw. Please publish 1.0.5 so that I don't have to do a stupid fork and publish of an exact copy of this library.

TypeError: n(...).Random is not a constructor

Hi,

I'm trying to use with React (with TypeScript)

Import

import { Random } from "random-js";
const random = new Random();

use

...
text += possible.charAt(Math.floor((random.integer(1, 1000)/1000  ) * possible.length));
...

It compiles correctly but then it throws error
TypeError: n(...).Random is not a constructor

Any idea?

interface incoherencies

I'm trying random-js.

The interfaces are strange. It would make sense to have parameters 1st, engine separated, like in Random.integer, Random.real, Random.bool

Pick:

  • actual Random.pick(engine, array[, begin[, end]])
  • expected: shouldn't it be Random.pick(array[, begin[, end]])(engine) ?

Generating an uuid4:

  • actual Random.uuid4(engine)
  • expected: shouldn't it be Random.uuid4()(engine) ?

And so on. Is it due to implementation constraints ? Or were you mirroring the C++ lib ?

Alternate API less performant?

As per the readme file:

Alternate API

There 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.

Why is it less performant to create r = Random(whateverEngine) than use Random.whateverMethod(engine)? Less performant in what terms, speed, crypto security, randomness?

Excuse me if this is somewhat obvious but I can't find anything that would lead me to the answer in the documentation nor source code.

Thank you in advance

Random.bool(percentage) not working properly

Would it be possible to explain what's going wrong here?

C:\Users\dhd\Desktop\data>node

var rand = require('random-js')
undefined
var nowDate = new Date().getTime();
undefined
var engine = rand.engines.mt19937().seed(nowDate);
undefined
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(50)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true
rand.bool(1)(engine)
true

Automatic dependency updates

As was mentioned in #65 (comment), automatic dependency updates would streamline development and ensure the PR section of this repo doesn't get clogged.
As long as tests pass, this shouldn't cause much issue in the long run with random-js.

Question: Use It In Games?

Hello,

Is it safe to use mt19937 engine (with autoSeed) for RNG games like Roulette? Are the results predictable? If somebody is collecting results, can they predict next drawn number based on previous collected results?

Thank you. :)

Add node crypto.randomBytes as engine

Would node's crypto.randomBytes be suitable as a fallback engine for server-side use cases? Basically, randomBytes produces 8-bit chunks that can be extended to the required size, then piped into random-js.

If it is worth the look, I'll try to submit some sample code or a PR.

MersenneTwister19937 is not defined

Code:-

const { Random } = require("random-js");

const random = new Random(MersenneTwister19937.autoSeed());

var value = random.integer(1, 100);
console.log(value)

Error:-

ReferenceError: MersenneTwister19937 is not defined
at Object. (D:\mersenneTwister\init.js:4:27)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:829:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

Any idea what i am doing wrong ?

Cannot read property 'nativeMath' of undefined (2.0.0-rc2)

just updated random-js in my package. It is throwing the following.

TypeError: Cannot read property 'nativeMath' of undefined
- at Object.<anonymous> (C:\Users\jesse\dev\wojakbot-nodejs\node_modules\rollkit\src\modules\dice.js:2:42)
- at Module._compile (internal/modules/cjs/loader.js:689:30)
- at Module._compile (C:\Users\jesse\dev\wojakbot-nodejs\node_modules\pirates\lib\index.js:99:24)
- at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
- at Object.newLoader [as .js] (C:\Users\jesse\dev\wojakbot-nodejs\node_modules\pirates\lib\index.js:104:7)
- at Module.load (internal/modules/cjs/loader.js:599:32)
- at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
- at Function.Module._load (internal/modules/cjs/loader.js:530:3)
- at Module.require (internal/modules/cjs/loader.js:637:17)
- at require (internal/modules/cjs/helpers.js:22:18)

dice.js

const Random = require('random-js');
const random = new Random(Random.engines.nativeMath);

cannot be imported properly in jest backend

(1) When used with es6 "import" keyword, I tested a working solution

import * as Random from "random-js"

let engine = Random.engines.mt19937().autoSeed()
let dist = new Random.default(engine)

(2) However, if I work it in jest (Facebook unit test framework for es6)

both the above codes and following codes do not work

var Random = require("random-js")

let engine = Random.engines.mt19937()
let dist = new Random(engine)

The constructor developed here is strange for me.

Force value to either min or max

I know this might be an odd question for a random library but, is there any way of forcing an engine to return the min or max value when using integer or real?

e.g.:

// force this to always return the min, 1
integer(1, 4);

// force this to always return the max, 4
integer(1, 4);

I've looked at creating a custom engine, and if the next() method returns 0 it seems to always return the min value:

const engine = {
  next() {
    return 0;
  },
};

integer(1, 4); // returns 1
integer(1, 4); // returns 1
integer(1, 4); // returns 1

I'm assuming it works by returning the number from the range, by index of the response from next(). But I can't find a way of forcing the max value.

Include ".js" in imports

Hi,

I'm looking for an isomorphic seeded random generator. The one you created looks good, however, its not completely isomorphic - the imports in the code are missing the ending ".js" file extension. Please consider switching to a fully isomorphic code.

Under "isomorphic" I mean the code, that works equally well in browser and node.js.

Add documentation on how to use this library without Node.js and/or with Webpack 5+

Webpack 5+ requires you to polyfill certain libraries on your own, and this should be documented so those who utilize this library for things other than Node.js itself can more easily prepare this library to run in browser webapps and the like. @Spacerat has a variant of this repo that doesn't utilize nodecrypto so that version can be pointed to along with the webpack polyfill method for this one

Also, as this is #69, definitely a nice issue ehehe

var random = new Random.Random() does not work when random-js is imported as a script

Thanks for this library, I'm unfortunately struggling to make use of it in script form, as indicated by the documentation.

Code snippet as follows:

  <script src="https://cdnjs.cloudflare.com/ajax/libs/random-js/1.0.8/random.min.js""></script>
  <script>
    var random = new Random.Random();
  </script>

This gives the following response:

Uncaught TypeError: Random.Random is not a constructor

Please could you advise on how to use the library in the above circumstance?

Version mismatch

bower.json still has it's version set to 1.0.6 instead of 1.0.8

This results in a warning when installing random-js via bower.

add `begin` and `end` to `.pick` and maybe `.picker`

This would provide the ability to intrinsically do Array.prototype.slice without doing so manually, thus allowing for performance optimization.

random.pick(['a', 'b', 'c', 'd', 'e'], 1, 3) //=> 'b', 'c', or 'd'.

Is it good to feed MersenneTwister19937 with array of same integers except one?

What's better for uniform random with MersenneTwister19937 seed? Here is pseudocode:

  1. One 32bit value with
const bit32 = 2147483647
const seed = random.integer(0, bit32)
MersenneTwister19937.seed(value)
  1. Or > 32bit value with array
const bit32 = 2147483647
const largeNumber = 56800235583
const rnd = random.integer(0, largeNumber)
const div = Math.floor(rnd / bit32)
const mod = rnd - (bit32 * div)
let seed = Array(div).fill(bit32)
seed.push(mod)
MersenneTwister19937.seedWithArray(seed)

Can't see any difference, but is it mathematically-correct?

548260550-ttmwuzkiqecfirjkhyeftlcjwdctfgos

feat: Add support for React Native

Currently if used on React Native, it throw an error stating that crypto module wasn't found.

Tested with the following code:

import { integer, MersenneTwister19937 } from 'random-js';

const engine = MersenneTwister19937.autoSeed();
return integer(min, max)(engine);

Can't build with webpack

Hello!

First off, thanks a lot for making this library. It seems to fit my use case perfectly, but I'm having some trouble getting started. I'm using Webpack with babel-loader and @babel/preset-typescript - it's a pretty simple setup, but when trying to build the project with random-js imported I get the following errors:

ERROR in ../node_modules/stream-browserify/index.js
Module not found: Error: Can't resolve 'readable-stream/duplex.js' in 'node_modules\stream-browserify'
 @ ../node_modules/stream-browserify/index.js 30:16-52
 @ ../node_modules/browserify-sign/browser/index.js
 @ ../node_modules/crypto-browserify/index.js
 @ ../node_modules/random-js/dist/random-js.esm.js

ERROR in ../node_modules/stream-browserify/index.js
Module not found: Error: Can't resolve 'readable-stream/passthrough.js' in 'node_modules\stream-browserify'
 @ ../node_modules/stream-browserify/index.js 32:21-62
 @ ../node_modules/browserify-sign/browser/index.js
 @ ../node_modules/crypto-browserify/index.js
 @ ../node_modules/random-js/dist/random-js.esm.js

ERROR in ../node_modules/stream-browserify/index.js
Module not found: Error: Can't resolve 'readable-stream/transform.js' in 'node_modules\stream-browserify'
 @ ../node_modules/stream-browserify/index.js 31:19-58
 @ ../node_modules/browserify-sign/browser/index.js
 @ ../node_modules/crypto-browserify/index.js
 @ ../node_modules/random-js/dist/random-js.esm.js

ERROR in ../node_modules/stream-browserify/index.js
Module not found: Error: Can't resolve 'readable-stream/writable.js' in 'node_modules\stream-browserify'
 @ ../node_modules/stream-browserify/index.js 29:18-56
 @ ../node_modules/browserify-sign/browser/index.js
 @ ../node_modules/crypto-browserify/index.js
 @ ../node_modules/random-js/dist/random-js.esm.js

Do you have have any pointers as to what could be wrong here? What can I do to pinpoint the problem?

I can post my webpack config and tsconfig if it's of interest.

Webpack version: 4.41.6
Node version: 12.16.0

Choose "best" engine automatically?

I understand if you don't select an engine, it uses Math.random(). Would it be possible to have a mode that uses the best engine for the currently running environment instead, i.e. window.crypto in modern browsers, node.js crypto in node, or fall back to Math.random()?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.