From 194e1a8896067b929315a603acad2e750dfa1526 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Wed, 24 Mar 2021 16:10:13 +0200 Subject: Give each faker instance its own random number generator Currently, every Faker instance shares the same random number generator instance which means that to seed one faker instance is to seed them all. This can result in duplicate data being generated all over the place. This just extracts the public API of the mersenne twister found in `vendor/mersenne.js` and creates a single instance of it per faker. This implementation is a tad sub-optimal since calling `seed()` on a faker instance will result in two redundant calls to `mersenne.init_genrand()`: one in `random.js` and the other in `datatype.js`. It would probably be more DRY to create the mersenne instance once in faker and then pass it into to the `Random` and `Datatype` instances, however, this takes the strategy of the smallest possible API change. --- lib/datatype.js | 8 +++----- lib/index.js | 3 +++ lib/mersenne.js | 31 +++++++++++++++++++++++++++++++ lib/random.js | 6 ++---- test/support/function-helpers.js | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 lib/mersenne.js diff --git a/lib/datatype.js b/lib/datatype.js index d2ec9ad2..02ea3759 100644 --- a/lib/datatype.js +++ b/lib/datatype.js @@ -1,5 +1,3 @@ -var mersenne = require('../vendor/mersenne'); - /** * * @namespace faker.datatype @@ -7,10 +5,10 @@ var mersenne = require('../vendor/mersenne'); function Datatype (faker, seed) { // Use a user provided seed if it is an array or number if (Array.isArray(seed) && seed.length) { - mersenne.seed_array(seed); + faker.mersenne.seed_array(seed); } else if(!isNaN(seed)) { - mersenne.seed(seed); + faker.mersenne.seed(seed); } /** @@ -47,7 +45,7 @@ function Datatype (faker, seed) { } var randomNumber = Math.floor( - mersenne.rand(max / options.precision, options.min / options.precision)); + faker.mersenne.rand(max / options.precision, options.min / options.precision)); // Workaround problem in Float point arithmetics for e.g. 6681493 / 0.01 randomNumber = randomNumber / (1 / options.precision); diff --git a/lib/index.js b/lib/index.js index f76a581e..a80580bd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -92,6 +92,9 @@ function Faker (opts) { var Unique = require('./unique'); self.unique = new Unique(self).unique; + var Mersenne = require('./mersenne'); + self.mersenne = new Mersenne(); + var Random = require('./random'); self.random = new Random(self); diff --git a/lib/mersenne.js b/lib/mersenne.js new file mode 100644 index 00000000..722ebc46 --- /dev/null +++ b/lib/mersenne.js @@ -0,0 +1,31 @@ +var Gen = require('../vendor/mersenne').MersenneTwister19937; + +function Mersenne() { + var gen = new Gen(); + gen.init_genrand((new Date).getTime() % 1000000000); + + this.rand = function(max, min) { + if (max === undefined) + { + min = 0; + max = 32768; + } + return Math.floor(gen.genrand_real2() * (max - min) + min); + } + this.seed = function(S) { + if (typeof(S) != 'number') + { + throw new Error("seed(S) must take numeric argument; is " + typeof(S)); + } + gen.init_genrand(S); + } + this.seed_array = function(A) { + if (typeof(A) != 'object') + { + throw new Error("seed_array(A) must take array of numbers; is " + typeof(A)); + } + gen.init_by_array(A, A.length); + } +} + +module.exports = Mersenne; diff --git a/lib/random.js b/lib/random.js index 4c2daaac..4443c555 100644 --- a/lib/random.js +++ b/lib/random.js @@ -1,5 +1,3 @@ -var mersenne = require('../vendor/mersenne'); - /** * Method to reduce array of characters * @param arr existing array of characters @@ -22,10 +20,10 @@ var arrayRemove = function (arr, values) { function Random (faker, seed) { // Use a user provided seed if it is an array or number if (Array.isArray(seed) && seed.length) { - mersenne.seed_array(seed); + faker.mersenne.seed_array(seed); } else if(!isNaN(seed)) { - mersenne.seed(seed); + faker.mersenne.seed(seed); } /** diff --git a/test/support/function-helpers.js b/test/support/function-helpers.js index 326da61a..5411ac71 100644 --- a/test/support/function-helpers.js +++ b/test/support/function-helpers.js @@ -9,7 +9,7 @@ var functionHelpers = {}; module.exports = functionHelpers; -var IGNORED_MODULES = ['locales', 'locale', 'localeFallback', 'definitions', 'fake', 'helpers']; +var IGNORED_MODULES = ['locales', 'locale', 'localeFallback', 'definitions', 'fake', 'helpers', 'mersenne']; var IGNORED_METHODS = { system: ['directoryPath', 'filePath'] // these are TODOs }; -- cgit v1.2.3 From eb3a5d23babd2ce0187b7aa761f745c5726e27ac Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 25 Mar 2021 09:47:19 +0200 Subject: =?UTF-8?q?=F0=9F=91=8D=F0=9F=8F=BCRemove=20old=20public=20API=20f?= =?UTF-8?q?rom=20vendor/mersenne.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/random.unit.js | 2 +- vendor/mersenne.js | 28 ---------------------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/test/random.unit.js b/test/random.unit.js index 147d7dbb..b45d347d 100644 --- a/test/random.unit.js +++ b/test/random.unit.js @@ -3,7 +3,7 @@ if (typeof module !== 'undefined') { var sinon = require('sinon'); var _ = require('lodash'); var faker = require('../index'); - var mersenne = require('../vendor/mersenne'); + var mersenne = new (require('../lib/mersenne')); } diff --git a/vendor/mersenne.js b/vendor/mersenne.js index edc4743c..4d9d0322 100644 --- a/vendor/mersenne.js +++ b/vendor/mersenne.js @@ -256,31 +256,3 @@ function MersenneTwister19937() // Export the twister class exports.MersenneTwister19937 = MersenneTwister19937; - -// Export a simplified function to generate random numbers -var gen = new MersenneTwister19937; -gen.init_genrand((new Date).getTime() % 1000000000); - -// Added max, min range functionality, Marak Squires Sept 11 2014 -exports.rand = function(max, min) { - if (max === undefined) - { - min = 0; - max = 32768; - } - return Math.floor(gen.genrand_real2() * (max - min) + min); -} -exports.seed = function(S) { - if (typeof(S) != 'number') - { - throw new Error("seed(S) must take numeric argument; is " + typeof(S)); - } - gen.init_genrand(S); -} -exports.seed_array = function(A) { - if (typeof(A) != 'object') - { - throw new Error("seed_array(A) must take array of numbers; is " + typeof(A)); - } - gen.init_by_array(A, A.length); -} \ No newline at end of file -- cgit v1.2.3