From 5aa747f7c0e6f4f67044d71139d2f2cf20256a32 Mon Sep 17 00:00:00 2001 From: Shinigami Date: Sat, 15 Oct 2022 07:49:26 +0800 Subject: refactor!: make mersenne internal (#1444) --- src/faker.ts | 13 +- src/internal/mersenne/mersenne.ts | 81 ++++++ src/internal/mersenne/twister.ts | 321 +++++++++++++++++++++ src/modules/datatype/index.ts | 7 +- src/modules/mersenne/index.ts | 81 ------ src/modules/mersenne/twister.ts | 320 -------------------- test/all_functional.spec.ts | 2 +- test/mersenne.spec.ts | 2 +- .../scripts/apidoc/examplesAndDeprecations.spec.ts | 16 +- 9 files changed, 423 insertions(+), 420 deletions(-) create mode 100644 src/internal/mersenne/mersenne.ts create mode 100644 src/internal/mersenne/twister.ts delete mode 100644 src/modules/mersenne/index.ts delete mode 100644 src/modules/mersenne/twister.ts diff --git a/src/faker.ts b/src/faker.ts index c42c313e..62a3bf6f 100644 --- a/src/faker.ts +++ b/src/faker.ts @@ -1,5 +1,6 @@ import type { LocaleDefinition } from './definitions'; import { FakerError } from './errors/faker-error'; +import { MersenneModule } from './internal/mersenne/mersenne'; import type { KnownLocale } from './locales'; import { AddressModule } from './modules/address'; import { AnimalModule } from './modules/animal'; @@ -16,7 +17,6 @@ import { HelpersModule } from './modules/helpers'; import { ImageModule } from './modules/image'; import { InternetModule } from './modules/internet'; import { LoremModule } from './modules/lorem'; -import { MersenneModule } from './modules/mersenne'; import { MusicModule } from './modules/music'; import { NameModule } from './modules/name'; import { PhoneModule } from './modules/phone'; @@ -74,10 +74,9 @@ export class Faker { readonly definitions: LocaleDefinition = this.initDefinitions(); - /** - * @internal - */ - readonly mersenne: MersenneModule = new MersenneModule(); + /** @internal */ + private readonly _mersenne: MersenneModule = new MersenneModule(); + readonly random: RandomModule = new RandomModule(this); readonly helpers: HelpersModule = new HelpersModule(this); @@ -241,9 +240,9 @@ export class Faker { seed: number | number[] = Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER) ): number | number[] { if (Array.isArray(seed) && seed.length) { - this.mersenne.seed_array(seed); + this._mersenne.seed_array(seed); } else if (!Array.isArray(seed) && !isNaN(seed)) { - this.mersenne.seed(seed); + this._mersenne.seed(seed); } return seed; diff --git a/src/internal/mersenne/mersenne.ts b/src/internal/mersenne/mersenne.ts new file mode 100644 index 00000000..16019e29 --- /dev/null +++ b/src/internal/mersenne/mersenne.ts @@ -0,0 +1,81 @@ +import { FakerError } from '../../errors/faker-error'; +import Gen from './twister'; + +/** + * Module to generate seed based random numbers. + * + * @internal + */ +export class MersenneModule { + private gen = new Gen(); + + constructor() { + this.gen.initGenrand(Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)); + + // Bind `this` so namespaced is working correctly + for (const name of Object.getOwnPropertyNames(MersenneModule.prototype)) { + if (name === 'constructor' || typeof this[name] !== 'function') { + continue; + } + this[name] = this[name].bind(this); + } + } + + /** + * Generates a random number between `[min, max)`. + * + * @param max The maximum number. Defaults to `32768`. + * @param min The minimum number. Defaults to `0`. + * + * @example + * faker.mersenne.rand() // 15515 + * faker.mersenne.rand(1000, 500) // 578 + * + * @since 5.5.0 + */ + rand(max = 32768, min = 0): number { + if (min > max) { + const temp = min; + min = max; + max = temp; + } + + return Math.floor(this.gen.genrandReal2() * (max - min) + min); + } + + /** + * Sets the seed to use. + * + * @param S The seed to use. + * @throws If the seed is not a `number`. + * + * @since 5.5.0 + */ + seed(S: number): void { + if (typeof S !== 'number') { + throw new FakerError( + `seed(S) must take numeric argument; is ${typeof S}` + ); + } + + this.gen.initGenrand(S); + } + + /** + * Sets the seed to use. + * + * @param A The seed to use. + * @throws If the seed is not a `number[]`. + * + * @since 5.5.0 + */ + seed_array(A: number[]): void { + if (typeof A !== 'object') { + throw new FakerError( + `seed_array(A) must take array of numbers; is ${typeof A}` + ); + } + + this.gen.initByArray(A, A.length); + } +} diff --git a/src/internal/mersenne/twister.ts b/src/internal/mersenne/twister.ts new file mode 100644 index 00000000..f7757842 --- /dev/null +++ b/src/internal/mersenne/twister.ts @@ -0,0 +1,321 @@ +/** + * Copyright (c) 2022 Faker + * + * This is a version of the original source code migrated to TypeScript and + * modified by the Faker team. + * + * Check LICENSE for more details on copyright. + * + * ----------------------------------------------------------------------------- + * + * Copyright (c) 2006 Y. Okada + * + * This program is a JavaScript version of Mersenne Twister, with concealment + * and encapsulation in class, an almost straight conversion from the original + * program, mt19937ar.c, translated by Y. Okada on July 17, 2006, and modified + * a little at July 20, 2006, but there are not any substantial differences. + * + * In this program, procedure descriptions and comments of original source code + * were not removed. + * + * Lines commented with //c// were originally descriptions of c procedure. + * And a few following lines are appropriate JavaScript descriptions. + * + * Lines commented with /* and *\/ are original comments. + * Lines commented with // are additional comments in this JavaScript version. + * + * Before using this version, create at least one instance of + * MersenneTwister19937 class, and initialize the each state, given below + * in C comments, of all the instances. + * + * ----------------------------------------------------------------------------- + * + * A C-program for MT19937, with initialization improved 2002/1/26. + * Coded by Takuji Nishimura and Makoto Matsumoto. + * + * Before using, initialize the state by using init_genrand(seed) + * or init_by_array(init_key, key_length). + * + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Any feedback is very welcome. + * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) + * + * @internal + */ +export default class MersenneTwister19937 { + private readonly N = 624; + private readonly M = 397; + private readonly MATRIX_A = 0x9908b0df; // constant vector a + private readonly UPPER_MASK = 0x80000000; // most significant w-r bits + private readonly LOWER_MASK = 0x7fffffff; // least significant r bits + private mt: number[] = new Array(this.N); // the array for the state vector + private mti = this.N + 1; // mti==N+1 means mt[N] is not initialized + + /** + * Returns a 32-bits unsigned integer from an operand to which applied a bit + * operator. + * + * @param n1 number to unsign + */ + private unsigned32(n1: number): number { + return n1 < 0 ? (n1 ^ this.UPPER_MASK) + this.UPPER_MASK : n1; + } + + /** + * Emulates lowerflow of a c 32-bits unsigned integer variable, instead of + * the operator -. These both arguments must be non-negative integers + * expressible using unsigned 32 bits. + * + * @param n1 dividend + * @param n2 divisor + */ + private subtraction32(n1: number, n2: number): number { + return n1 < n2 + ? this.unsigned32((0x100000000 - (n2 - n1)) & 0xffffffff) + : n1 - n2; + } + + /** + * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator +. + * these both arguments must be non-negative integers expressible using unsigned 32 bits. + * + * @param n1 number one for addition + * @param n2 number two for addition + */ + private addition32(n1: number, n2: number): number { + return this.unsigned32((n1 + n2) & 0xffffffff); + } + + /** + * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator *. + * These both arguments must be non-negative integers expressible using unsigned 32 bits. + * + * @param n1 number one for multiplication + * @param n2 number two for multiplication + */ + private multiplication32(n1: number, n2: number): number { + let sum = 0; + for (let i = 0; i < 32; ++i) { + if ((n1 >>> i) & 0x1) { + sum = this.addition32(sum, this.unsigned32(n2 << i)); + } + } + return sum; + } + + /** + * Initializes mt[N] with a seed. + * + * @param seed the seed to use + */ + initGenrand(seed: number): void { + this.mt[0] = this.unsigned32(seed & 0xffffffff); + for (this.mti = 1; this.mti < this.N; this.mti++) { + this.mt[this.mti] = + //(1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + this.addition32( + this.multiplication32( + 1812433253, + this.unsigned32( + this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30) + ) + ), + this.mti + ); + + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + this.mt[this.mti] = this.unsigned32(this.mt[this.mti] & 0xffffffff); + } + } + + /** + * Initialize by an array with array-length. + * + * @param initKey is the array for initializing keys + * @param keyLength is its length + */ + initByArray(initKey: number[], keyLength: number): void { + this.initGenrand(19650218); + let i = 1; + let j = 0; + let k = this.N > keyLength ? this.N : keyLength; + for (; k; k--) { + // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525)) + init_key[j] + j; + this.mt[i] = this.addition32( + this.addition32( + this.unsigned32( + this.mt[i] ^ + this.multiplication32( + this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)), + 1664525 + ) + ), + initKey[j] + ), + j + ); + // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines + this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff); + i++; + j++; + if (i >= this.N) { + this.mt[0] = this.mt[this.N - 1]; + i = 1; + } + if (j >= keyLength) { + j = 0; + } + } + for (k = this.N - 1; k; k--) { + // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941)) - i + this.mt[i] = this.subtraction32( + this.unsigned32( + this.mt[i] ^ + this.multiplication32( + this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)), + 1566083941 + ) + ), + i + ); + // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines + this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff); + i++; + if (i >= this.N) { + this.mt[0] = this.mt[this.N - 1]; + i = 1; + } + } + this.mt[0] = 0x80000000; // MSB is 1; assuring non-zero initial array + } + + // moved outside of genrandInt32() by jwatte 2010-11-17; generate less garbage + private mag01 = [0x0, this.MATRIX_A]; + + /** + * Generates a random number on [0,2^32]-interval + */ + genrandInt32(): number { + let y: number; + + if (this.mti >= this.N) { + // generate N words at one time + let kk: number; + + // if initGenrand() has not been called a default initial seed is used + if (this.mti === this.N + 1) { + this.initGenrand(5489); + } + + for (kk = 0; kk < this.N - this.M; kk++) { + y = this.unsigned32( + (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) + ); + + this.mt[kk] = this.unsigned32( + this.mt[kk + this.M] ^ (y >>> 1) ^ this.mag01[y & 0x1] + ); + } + + for (; kk < this.N - 1; kk++) { + y = this.unsigned32( + (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) + ); + + this.mt[kk] = this.unsigned32( + this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ this.mag01[y & 0x1] + ); + } + + y = this.unsigned32( + (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK) + ); + + this.mt[this.N - 1] = this.unsigned32( + this.mt[this.M - 1] ^ (y >>> 1) ^ this.mag01[y & 0x1] + ); + + this.mti = 0; + } + + y = this.mt[this.mti++]; + + // Tempering + y = this.unsigned32(y ^ (y >>> 11)); + y = this.unsigned32(y ^ ((y << 7) & 0x9d2c5680)); + y = this.unsigned32(y ^ ((y << 15) & 0xefc60000)); + y = this.unsigned32(y ^ (y >>> 18)); + + return y; + } + + /** + * Generates a random number on [0,2^32]-interval + */ + genrandInt31(): number { + return this.genrandInt32() >>> 1; + } + + /** + * Generates a random number on [0,1]-real-interval + */ + genrandReal1(): number { + return this.genrandInt32() * (1.0 / 4294967295.0); // divided by 2^32-1 + } + + /** + * Generates a random number on [0,1)-real-interval + */ + genrandReal2(): number { + return this.genrandInt32() * (1.0 / 4294967296.0); // divided by 2^32 + } + + /** + * Generates a random number on (0,1)-real-interval + */ + genrandReal3(): number { + return (this.genrandInt32() + 0.5) * (1.0 / 4294967296.0); // divided by 2^32 + } + + /** + * Generates a random number on [0,1) with 53-bit resolution + */ + genrandRes53(): number { + const a = this.genrandInt32() >>> 5, + b = this.genrandInt32() >>> 6; + return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); + } + // These real versions are due to Isaku Wada, 2002/01/09 +} diff --git a/src/modules/datatype/index.ts b/src/modules/datatype/index.ts index 336f8f9f..4c522d53 100644 --- a/src/modules/datatype/index.ts +++ b/src/modules/datatype/index.ts @@ -1,5 +1,6 @@ import type { Faker } from '../..'; import { FakerError } from '../../errors/faker-error'; +import type { MersenneModule } from '../../internal/mersenne/mersenne'; /** * Module to generate various primitive values and data types. @@ -54,8 +55,12 @@ export class DatatypeModule { throw new FakerError(`Max ${max} should be greater than min ${min}.`); } + const mersenne: MersenneModule = + // @ts-expect-error: access private member field + this.faker._mersenne; + const randomNumber = Math.floor( - this.faker.mersenne.rand(max / precision + 1, min / precision) + mersenne.rand(max / precision + 1, min / precision) ); // Workaround problem in float point arithmetics for e.g. 6681493 / 0.01 diff --git a/src/modules/mersenne/index.ts b/src/modules/mersenne/index.ts deleted file mode 100644 index 16019e29..00000000 --- a/src/modules/mersenne/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { FakerError } from '../../errors/faker-error'; -import Gen from './twister'; - -/** - * Module to generate seed based random numbers. - * - * @internal - */ -export class MersenneModule { - private gen = new Gen(); - - constructor() { - this.gen.initGenrand(Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)); - - // Bind `this` so namespaced is working correctly - for (const name of Object.getOwnPropertyNames(MersenneModule.prototype)) { - if (name === 'constructor' || typeof this[name] !== 'function') { - continue; - } - this[name] = this[name].bind(this); - } - } - - /** - * Generates a random number between `[min, max)`. - * - * @param max The maximum number. Defaults to `32768`. - * @param min The minimum number. Defaults to `0`. - * - * @example - * faker.mersenne.rand() // 15515 - * faker.mersenne.rand(1000, 500) // 578 - * - * @since 5.5.0 - */ - rand(max = 32768, min = 0): number { - if (min > max) { - const temp = min; - min = max; - max = temp; - } - - return Math.floor(this.gen.genrandReal2() * (max - min) + min); - } - - /** - * Sets the seed to use. - * - * @param S The seed to use. - * @throws If the seed is not a `number`. - * - * @since 5.5.0 - */ - seed(S: number): void { - if (typeof S !== 'number') { - throw new FakerError( - `seed(S) must take numeric argument; is ${typeof S}` - ); - } - - this.gen.initGenrand(S); - } - - /** - * Sets the seed to use. - * - * @param A The seed to use. - * @throws If the seed is not a `number[]`. - * - * @since 5.5.0 - */ - seed_array(A: number[]): void { - if (typeof A !== 'object') { - throw new FakerError( - `seed_array(A) must take array of numbers; is ${typeof A}` - ); - } - - this.gen.initByArray(A, A.length); - } -} diff --git a/src/modules/mersenne/twister.ts b/src/modules/mersenne/twister.ts deleted file mode 100644 index 5859f3ae..00000000 --- a/src/modules/mersenne/twister.ts +++ /dev/null @@ -1,320 +0,0 @@ -/** - * Copyright (c) 2022 Faker - * - * This is a version of the original source code migrated to TypeScript and - * modified by the Faker team. - * - * Check LICENSE for more details on copyright. - * - * ----------------------------------------------------------------------------- - * - * Copyright (c) 2006 Y. Okada - * - * This program is a JavaScript version of Mersenne Twister, with concealment - * and encapsulation in class, an almost straight conversion from the original - * program, mt19937ar.c, translated by Y. Okada on July 17, 2006, and modified - * a little at July 20, 2006, but there are not any substantial differences. - * - * In this program, procedure descriptions and comments of original source code - * were not removed. - * - * Lines commented with //c// were originally descriptions of c procedure. - * And a few following lines are appropriate JavaScript descriptions. - * - * Lines commented with /* and *\/ are original comments. - * Lines commented with // are additional comments in this JavaScript version. - * - * Before using this version, create at least one instance of - * MersenneTwister19937 class, and initialize the each state, given below - * in C comments, of all the instances. - * - * ----------------------------------------------------------------------------- - * - * A C-program for MT19937, with initialization improved 2002/1/26. - * Coded by Takuji Nishimura and Makoto Matsumoto. - * - * Before using, initialize the state by using init_genrand(seed) - * or init_by_array(init_key, key_length). - * - * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * Any feedback is very welcome. - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html - * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) - */ - -export default class MersenneTwister19937 { - private readonly N = 624; - private readonly M = 397; - private readonly MATRIX_A = 0x9908b0df; // constant vector a - private readonly UPPER_MASK = 0x80000000; // most significant w-r bits - private readonly LOWER_MASK = 0x7fffffff; // least significant r bits - private mt: number[] = new Array(this.N); // the array for the state vector - private mti = this.N + 1; // mti==N+1 means mt[N] is not initialized - - /** - * Returns a 32-bits unsigned integer from an operand to which applied a bit - * operator. - * - * @param n1 number to unsign - */ - private unsigned32(n1: number): number { - return n1 < 0 ? (n1 ^ this.UPPER_MASK) + this.UPPER_MASK : n1; - } - - /** - * Emulates lowerflow of a c 32-bits unsigned integer variable, instead of - * the operator -. These both arguments must be non-negative integers - * expressible using unsigned 32 bits. - * - * @param n1 dividend - * @param n2 divisor - */ - private subtraction32(n1: number, n2: number): number { - return n1 < n2 - ? this.unsigned32((0x100000000 - (n2 - n1)) & 0xffffffff) - : n1 - n2; - } - - /** - * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator +. - * these both arguments must be non-negative integers expressible using unsigned 32 bits. - * - * @param n1 number one for addition - * @param n2 number two for addition - */ - private addition32(n1: number, n2: number): number { - return this.unsigned32((n1 + n2) & 0xffffffff); - } - - /** - * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator *. - * These both arguments must be non-negative integers expressible using unsigned 32 bits. - * - * @param n1 number one for multiplication - * @param n2 number two for multiplication - */ - private multiplication32(n1: number, n2: number): number { - let sum = 0; - for (let i = 0; i < 32; ++i) { - if ((n1 >>> i) & 0x1) { - sum = this.addition32(sum, this.unsigned32(n2 << i)); - } - } - return sum; - } - - /** - * Initializes mt[N] with a seed. - * - * @param seed the seed to use - */ - initGenrand(seed: number): void { - this.mt[0] = this.unsigned32(seed & 0xffffffff); - for (this.mti = 1; this.mti < this.N; this.mti++) { - this.mt[this.mti] = - //(1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); - this.addition32( - this.multiplication32( - 1812433253, - this.unsigned32( - this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30) - ) - ), - this.mti - ); - - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array mt[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - this.mt[this.mti] = this.unsigned32(this.mt[this.mti] & 0xffffffff); - } - } - - /** - * Initialize by an array with array-length. - * - * @param initKey is the array for initializing keys - * @param keyLength is its length - */ - initByArray(initKey: number[], keyLength: number): void { - this.initGenrand(19650218); - let i = 1; - let j = 0; - let k = this.N > keyLength ? this.N : keyLength; - for (; k; k--) { - // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525)) + init_key[j] + j; - this.mt[i] = this.addition32( - this.addition32( - this.unsigned32( - this.mt[i] ^ - this.multiplication32( - this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)), - 1664525 - ) - ), - initKey[j] - ), - j - ); - // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines - this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff); - i++; - j++; - if (i >= this.N) { - this.mt[0] = this.mt[this.N - 1]; - i = 1; - } - if (j >= keyLength) { - j = 0; - } - } - for (k = this.N - 1; k; k--) { - // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941)) - i - this.mt[i] = this.subtraction32( - this.unsigned32( - this.mt[i] ^ - this.multiplication32( - this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)), - 1566083941 - ) - ), - i - ); - // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines - this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff); - i++; - if (i >= this.N) { - this.mt[0] = this.mt[this.N - 1]; - i = 1; - } - } - this.mt[0] = 0x80000000; // MSB is 1; assuring non-zero initial array - } - - // moved outside of genrandInt32() by jwatte 2010-11-17; generate less garbage - private mag01 = [0x0, this.MATRIX_A]; - - /** - * Generates a random number on [0,2^32]-interval - */ - genrandInt32(): number { - let y: number; - - if (this.mti >= this.N) { - // generate N words at one time - let kk: number; - - // if initGenrand() has not been called a default initial seed is used - if (this.mti === this.N + 1) { - this.initGenrand(5489); - } - - for (kk = 0; kk < this.N - this.M; kk++) { - y = this.unsigned32( - (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) - ); - - this.mt[kk] = this.unsigned32( - this.mt[kk + this.M] ^ (y >>> 1) ^ this.mag01[y & 0x1] - ); - } - - for (; kk < this.N - 1; kk++) { - y = this.unsigned32( - (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK) - ); - - this.mt[kk] = this.unsigned32( - this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ this.mag01[y & 0x1] - ); - } - - y = this.unsigned32( - (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK) - ); - - this.mt[this.N - 1] = this.unsigned32( - this.mt[this.M - 1] ^ (y >>> 1) ^ this.mag01[y & 0x1] - ); - - this.mti = 0; - } - - y = this.mt[this.mti++]; - - // Tempering - y = this.unsigned32(y ^ (y >>> 11)); - y = this.unsigned32(y ^ ((y << 7) & 0x9d2c5680)); - y = this.unsigned32(y ^ ((y << 15) & 0xefc60000)); - y = this.unsigned32(y ^ (y >>> 18)); - - return y; - } - - /** - * Generates a random number on [0,2^32]-interval - */ - genrandInt31(): number { - return this.genrandInt32() >>> 1; - } - - /** - * Generates a random number on [0,1]-real-interval - */ - genrandReal1(): number { - return this.genrandInt32() * (1.0 / 4294967295.0); // divided by 2^32-1 - } - - /** - * Generates a random number on [0,1)-real-interval - */ - genrandReal2(): number { - return this.genrandInt32() * (1.0 / 4294967296.0); // divided by 2^32 - } - - /** - * Generates a random number on (0,1)-real-interval - */ - genrandReal3(): number { - return (this.genrandInt32() + 0.5) * (1.0 / 4294967296.0); // divided by 2^32 - } - - /** - * Generates a random number on [0,1) with 53-bit resolution - */ - genrandRes53(): number { - const a = this.genrandInt32() >>> 5, - b = this.genrandInt32() >>> 6; - return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); - } - // These real versions are due to Isaku Wada, 2002/01/09 -} diff --git a/test/all_functional.spec.ts b/test/all_functional.spec.ts index f857b84c..5ae065be 100644 --- a/test/all_functional.spec.ts +++ b/test/all_functional.spec.ts @@ -8,7 +8,7 @@ const IGNORED_MODULES = [ 'definitions', 'fake', 'helpers', - 'mersenne', + '_mersenne', ]; function isTestableModule(mod: string) { diff --git a/test/mersenne.spec.ts b/test/mersenne.spec.ts index 62b65a69..6b0a3125 100644 --- a/test/mersenne.spec.ts +++ b/test/mersenne.spec.ts @@ -1,6 +1,6 @@ import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; import { FakerError } from '../src/errors/faker-error'; -import { MersenneModule } from '../src/modules/mersenne'; +import { MersenneModule } from '../src/internal/mersenne/mersenne'; import { seededRuns } from './support/seededRuns'; const minMaxTestCases = [ diff --git a/test/scripts/apidoc/examplesAndDeprecations.spec.ts b/test/scripts/apidoc/examplesAndDeprecations.spec.ts index 37d61399..772307a9 100644 --- a/test/scripts/apidoc/examplesAndDeprecations.spec.ts +++ b/test/scripts/apidoc/examplesAndDeprecations.spec.ts @@ -32,15 +32,13 @@ describe('examples and deprecations', () => { const modules: Record = selectApiModules( project - ) - .filter((module) => module.name !== 'MersenneModule') - .reduce( - (a, v) => ({ - ...a, - [v.name]: v.getChildrenByKind(ReflectionKind.Method), - }), - {} - ); + ).reduce( + (a, v) => ({ + ...a, + [v.name]: v.getChildrenByKind(ReflectionKind.Method), + }), + {} + ); const consoleSpies: Array = Object.keys(console) .filter((key) => typeof console[key] === 'function') -- cgit v1.2.3