@cloudglides/nox 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-on-tag.yml +67 -0
- package/IMPROVEMENTS.md +58 -0
- package/LICENSE +15 -0
- package/README.md +119 -0
- package/docs/API.md +70 -0
- package/package.json +25 -0
- package/src/core.js +8 -0
- package/src/generators/index.js +7 -0
- package/src/generators/logistic.js +19 -0
- package/src/generators/mixer.js +20 -0
- package/src/generators/mt19937.js +74 -0
- package/src/generators/pcg64.js +44 -0
- package/src/generators/splitmix64.js +32 -0
- package/src/generators/tent.js +24 -0
- package/src/generators/xorshift64.js +38 -0
- package/src/index.d.ts +114 -0
- package/src/index.js +31 -0
- package/src/presets.js +15 -0
- package/src/rng.js +141 -0
- package/src/utils/bits.js +25 -0
- package/src/utils/categorical.js +57 -0
- package/src/utils/combinatorics.js +85 -0
- package/src/utils/distributions-extra.js +32 -0
- package/src/utils/distributions-special.js +21 -0
- package/src/utils/distributions.js +69 -0
- package/src/utils/entropy.js +57 -0
- package/src/utils/index.js +30 -0
- package/src/utils/noise.js +81 -0
- package/src/utils/sampling.js +106 -0
- package/src/utils/seed.js +14 -0
- package/src/utils/seeding.js +37 -0
- package/src/utils/sequence.js +53 -0
- package/src/utils/state.js +39 -0
- package/src/utils/statistics.js +127 -0
- package/src/utils/stochastic.js +32 -0
- package/test/advanced.js +71 -0
- package/test/basic.js +13 -0
- package/test/benchmark.js +35 -0
- package/test/comprehensive.js +100 -0
- package/test/profile.js +73 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Build on Tag
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- 'v*'
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- uses: pnpm/action-setup@v2
|
|
18
|
+
with:
|
|
19
|
+
version: 10
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: '20'
|
|
24
|
+
cache: 'pnpm'
|
|
25
|
+
registry-url: 'https://registry.npmjs.org'
|
|
26
|
+
|
|
27
|
+
- name: Extract version from tag
|
|
28
|
+
id: version
|
|
29
|
+
run: |
|
|
30
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
31
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
32
|
+
|
|
33
|
+
- name: Update package.json version
|
|
34
|
+
run: |
|
|
35
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
36
|
+
pnpm exec jq --arg v "$VERSION" '.version = $v' package.json > package.json.tmp
|
|
37
|
+
mv package.json.tmp package.json
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
run: pnpm install
|
|
41
|
+
|
|
42
|
+
- name: Run tests
|
|
43
|
+
run: pnpm test
|
|
44
|
+
|
|
45
|
+
- name: Publish to npm
|
|
46
|
+
run: npm publish
|
|
47
|
+
env:
|
|
48
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
49
|
+
|
|
50
|
+
- name: Get commit history
|
|
51
|
+
id: commits
|
|
52
|
+
run: |
|
|
53
|
+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || git rev-list --max-parents=0 HEAD)
|
|
54
|
+
COMMITS=$(git log $PREV_TAG..HEAD --oneline --no-decorate)
|
|
55
|
+
{
|
|
56
|
+
echo "commit_log<<EOF"
|
|
57
|
+
echo "$COMMITS"
|
|
58
|
+
echo "EOF"
|
|
59
|
+
} >> $GITHUB_OUTPUT
|
|
60
|
+
|
|
61
|
+
- name: Create GitHub Release
|
|
62
|
+
uses: softprops/action-gh-release@v1
|
|
63
|
+
with:
|
|
64
|
+
body: ${{ steps.commits.outputs.commit_log }}
|
|
65
|
+
generate_release_notes: true
|
|
66
|
+
env:
|
|
67
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/IMPROVEMENTS.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Improvements Made (Hour 2)
|
|
2
|
+
|
|
3
|
+
## Batch Operations
|
|
4
|
+
- Added `batch(count, fn)` - Execute custom function n times
|
|
5
|
+
- Added `floats(count)` - Generate array of floats
|
|
6
|
+
- Added `ints(count, max)` - Generate array of integers
|
|
7
|
+
- Added `bools(count, probability)` - Generate array of booleans
|
|
8
|
+
|
|
9
|
+
## RNG API Enhancements
|
|
10
|
+
- Added `range(min, max, step)` - Pick random value from stepped range
|
|
11
|
+
- Added `choice(arr)` - Pick random element from array
|
|
12
|
+
- Better error messages with TypeError vs RangeError distinctions
|
|
13
|
+
|
|
14
|
+
## Statistical Improvements
|
|
15
|
+
- Added `kolmogorovSmirnovTest(data)` - KS goodness-of-fit test
|
|
16
|
+
- Added `meanTest(data, expected)` - Test mean of distribution
|
|
17
|
+
- Added `varianceTest(data, expected)` - Test variance of distribution
|
|
18
|
+
- All tests return detailed result objects with pass/fail indicators
|
|
19
|
+
|
|
20
|
+
## Sampling Enhancements
|
|
21
|
+
- Improved `weightedPick()` with comprehensive validation
|
|
22
|
+
- Improved `weightedSample()` with type checking
|
|
23
|
+
- Improved `reservoirSample()` with better error handling
|
|
24
|
+
|
|
25
|
+
## Generator Optimizations
|
|
26
|
+
- Removed modulo bias in `nextInt()` - uses rejection sampling instead
|
|
27
|
+
- Applied to: PCG64, Xorshift64, Splitmix64, MT19937
|
|
28
|
+
- Ensures uniform distribution across all ranges
|
|
29
|
+
|
|
30
|
+
## Performance & Caching
|
|
31
|
+
- Added crypto cache in entropy source for performance
|
|
32
|
+
- Added `clearCryptoCache()` export for testing
|
|
33
|
+
- Better entropy mixing with proper BigInt operations
|
|
34
|
+
|
|
35
|
+
## Type Safety
|
|
36
|
+
- Added `IGenerator` interface for type consistency
|
|
37
|
+
- Added `GeneratorConstructor` type definition
|
|
38
|
+
- Added generic types to shuffle, pick, sample functions
|
|
39
|
+
- Added test result interfaces: `TestResult`, `KSTestResult`
|
|
40
|
+
- Complete TypeScript definitions for all new APIs
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
- Updated README with batch operations examples
|
|
44
|
+
- Added weighted sampling section
|
|
45
|
+
- Added statistical tests section
|
|
46
|
+
- Enhanced generator selection documentation
|
|
47
|
+
|
|
48
|
+
## Testing
|
|
49
|
+
- Added comprehensive test suite (test/comprehensive.js)
|
|
50
|
+
- Added advanced features test (test/advanced.js)
|
|
51
|
+
- All tests pass successfully
|
|
52
|
+
|
|
53
|
+
## Code Quality
|
|
54
|
+
- Total lines: 1107 → 1318 (+211)
|
|
55
|
+
- Files modified: 10
|
|
56
|
+
- Lines added/changed: 286
|
|
57
|
+
- Consistent error handling patterns
|
|
58
|
+
- Full backward compatibility maintained
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# nox
|
|
2
|
+
|
|
3
|
+
Simple, unpredictable random number generator.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install nox
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { rng, deterministic } from 'nox';
|
|
15
|
+
|
|
16
|
+
const r = rng();
|
|
17
|
+
|
|
18
|
+
r.nextFloat(); // 0.742...
|
|
19
|
+
r.nextInt(100); // 47
|
|
20
|
+
r.int(1, 100); // 73
|
|
21
|
+
r.bool(0.3); // true/false (30% chance)
|
|
22
|
+
r.range(10, 20, 2); // Pick from range: 10, 12, 14, 16, 18, 20
|
|
23
|
+
r.choice([1, 2, 3]); // Pick one element
|
|
24
|
+
|
|
25
|
+
// Batch operations
|
|
26
|
+
r.floats(5); // [0.123, 0.456, ...]
|
|
27
|
+
r.ints(5, 100); // [47, 82, 23, ...]
|
|
28
|
+
r.bools(5); // [true, false, true, ...]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Reproducible
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
import { deterministic } from 'nox';
|
|
35
|
+
|
|
36
|
+
const r = deterministic(42);
|
|
37
|
+
// Always same sequence
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Distributions
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
import { rng, normal, exponential, uniform, poisson } from 'nox';
|
|
44
|
+
|
|
45
|
+
const r = rng();
|
|
46
|
+
|
|
47
|
+
normal(r, mean=0, stddev=1);
|
|
48
|
+
exponential(r, lambda=1);
|
|
49
|
+
uniform(r, min=0, max=1);
|
|
50
|
+
poisson(r, lambda=5);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Sampling
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import { rng, shuffle, pick, sample } from 'nox';
|
|
57
|
+
|
|
58
|
+
const r = rng();
|
|
59
|
+
|
|
60
|
+
shuffle([1, 2, 3], r);
|
|
61
|
+
pick(['a', 'b', 'c'], r);
|
|
62
|
+
sample([1, 2, 3, 4, 5], 3, r);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## State
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
import { rng, saveState, restoreState } from 'nox';
|
|
69
|
+
|
|
70
|
+
const r = rng();
|
|
71
|
+
const snapshot = saveState(r);
|
|
72
|
+
|
|
73
|
+
r.nextFloat();
|
|
74
|
+
restoreState(r, snapshot);
|
|
75
|
+
r.nextFloat(); // Same value
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Weighted Sampling
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
import { rng, weightedPick, reservoirSample } from 'nox';
|
|
82
|
+
|
|
83
|
+
const r = rng();
|
|
84
|
+
const items = ['A', 'B', 'C'];
|
|
85
|
+
const weights = [0.5, 0.3, 0.2];
|
|
86
|
+
|
|
87
|
+
weightedPick(items, weights, r); // Pick with probabilities
|
|
88
|
+
reservoirSample(stream, k, r); // Sample k from large stream
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Statistical Tests
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
import { rng, meanTest, varianceTest, kolmogorovSmirnovTest } from 'nox';
|
|
95
|
+
|
|
96
|
+
const r = rng();
|
|
97
|
+
const data = r.floats(1000);
|
|
98
|
+
|
|
99
|
+
const mean = meanTest(data); // Test mean ≈ 0.5
|
|
100
|
+
const variance = varianceTest(data); // Test variance ≈ 1/12
|
|
101
|
+
const ks = kolmogorovSmirnovTest(data); // Test uniform distribution
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Generators
|
|
105
|
+
|
|
106
|
+
For reproducible results or specific generator properties:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
import { RNG, PCG64, MT19937, Xorshift64, Splitmix64 } from 'nox';
|
|
110
|
+
|
|
111
|
+
const r = new RNG(PCG64, seed); // PCG64 (default, fast, high quality)
|
|
112
|
+
const r = new RNG(MT19937, seed); // MT19937 (Mersenne Twister)
|
|
113
|
+
const r = new RNG(Xorshift64, seed); // Xorshift64 (simple, fast)
|
|
114
|
+
const r = new RNG(Splitmix64, seed); // Splitmix64 (statistical mixing)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
ISC
|
package/docs/API.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# API
|
|
2
|
+
|
|
3
|
+
## Core
|
|
4
|
+
|
|
5
|
+
### `rng()`
|
|
6
|
+
Create a random number generator with automatic entropy.
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
const r = rng();
|
|
10
|
+
r.nextFloat(); // [0, 1)
|
|
11
|
+
r.nextInt(100); // [0, 100)
|
|
12
|
+
r.int(1, 100); // [1, 100]
|
|
13
|
+
r.bool(0.3); // true 30% of time
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### `deterministic(seed)`
|
|
17
|
+
Create a generator with fixed seed for reproducibility.
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const r = deterministic(42);
|
|
21
|
+
// Always same sequence
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Distributions
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { rng, normal, exponential, uniform, poisson } from 'nox';
|
|
28
|
+
|
|
29
|
+
const r = rng();
|
|
30
|
+
normal(r, mean=0, stddev=1);
|
|
31
|
+
exponential(r, lambda=1);
|
|
32
|
+
uniform(r, 0, 1);
|
|
33
|
+
poisson(r, lambda=5);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Sampling
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { rng, shuffle, pick, sample } from 'nox';
|
|
40
|
+
|
|
41
|
+
const r = rng();
|
|
42
|
+
shuffle([1, 2, 3], r); // Shuffled copy
|
|
43
|
+
pick(['a', 'b', 'c'], r); // Random element
|
|
44
|
+
sample([1, 2, 3, 4, 5], 3, r); // 3 elements without replacement
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## State
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import { rng, saveState, restoreState } from 'nox';
|
|
51
|
+
|
|
52
|
+
const r = rng();
|
|
53
|
+
const snapshot = saveState(r);
|
|
54
|
+
|
|
55
|
+
r.nextFloat();
|
|
56
|
+
restoreState(r, snapshot);
|
|
57
|
+
r.nextFloat(); // Same as before
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Generators
|
|
61
|
+
|
|
62
|
+
Advanced: use specific generators directly.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import { PCG64, MT19937, Xorshift64 } from 'nox';
|
|
66
|
+
|
|
67
|
+
new PCG64(seed); // Best quality (default)
|
|
68
|
+
new MT19937(seed); // Classic, very fast
|
|
69
|
+
new Xorshift64(seed); // Fast, good quality
|
|
70
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudglides/nox",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Unpredictable random number generator with multiple algorithms and distributions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"types": "src/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "node test/basic.js",
|
|
10
|
+
"bench": "node test/benchmark.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"random",
|
|
14
|
+
"rng",
|
|
15
|
+
"generator",
|
|
16
|
+
"chaotic",
|
|
17
|
+
"stochastic"
|
|
18
|
+
],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"packageManager": "pnpm@10.24.0",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/core.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { rng, RNG } from './rng.js';
|
|
2
|
+
export { deterministic } from './presets.js';
|
|
3
|
+
|
|
4
|
+
export { normal, exponential, uniform, poisson } from './utils/distributions.js';
|
|
5
|
+
export { shuffle, pick, sample } from './utils/sequence.js';
|
|
6
|
+
export { saveState, restoreState, cloneGenerator } from './utils/state.js';
|
|
7
|
+
export { weightedPick, weightedSample, reservoirSample } from './utils/sampling.js';
|
|
8
|
+
export { meanTest, varianceTest, kolmogorovSmirnovTest } from './utils/statistics.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Xorshift64 } from './xorshift64.js';
|
|
2
|
+
export { Logistic } from './logistic.js';
|
|
3
|
+
export { Tent } from './tent.js';
|
|
4
|
+
export { Splitmix64 } from './splitmix64.js';
|
|
5
|
+
export { PCG64 } from './pcg64.js';
|
|
6
|
+
export { MT19937 } from './mt19937.js';
|
|
7
|
+
export { Mixer } from './mixer.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class Logistic {
|
|
2
|
+
constructor(seed = 0.5, r = 3.99) {
|
|
3
|
+
this.x = seed;
|
|
4
|
+
this.r = r;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
next() {
|
|
8
|
+
this.x = this.r * this.x * (1 - this.x);
|
|
9
|
+
return this.x;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
nextInt(max = 2147483647) {
|
|
13
|
+
return Math.floor(this.next() * max);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
nextFloat() {
|
|
17
|
+
return this.next();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class Mixer {
|
|
2
|
+
constructor(rng1, rng2) {
|
|
3
|
+
this.rng1 = rng1;
|
|
4
|
+
this.rng2 = rng2;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
next() {
|
|
8
|
+
return this.rng1.next() ^ this.rng2.next();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
nextInt(max = 2147483647) {
|
|
12
|
+
const v1 = this.rng1.nextInt(max);
|
|
13
|
+
const v2 = this.rng2.nextInt(max);
|
|
14
|
+
return (v1 + v2) % max;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
nextFloat() {
|
|
18
|
+
return (this.rng1.nextFloat() + this.rng2.nextFloat()) / 2;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export class MT19937 {
|
|
2
|
+
constructor(seed = 5489) {
|
|
3
|
+
this.N = 624;
|
|
4
|
+
this.M = 397;
|
|
5
|
+
this.MATRIX_A = 0x9908b0df;
|
|
6
|
+
this.UPPER_MASK = 0x80000000;
|
|
7
|
+
this.LOWER_MASK = 0x7fffffff;
|
|
8
|
+
|
|
9
|
+
this.mt = new Array(this.N);
|
|
10
|
+
this.mti = this.N + 1;
|
|
11
|
+
|
|
12
|
+
this.init(seed);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
init(seed) {
|
|
16
|
+
const s = typeof seed === 'bigint' ? Number(seed) : seed;
|
|
17
|
+
this.mt[0] = (s >>> 0) & 0xffffffff;
|
|
18
|
+
|
|
19
|
+
for (let i = 1; i < this.N; i++) {
|
|
20
|
+
const x = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
|
|
21
|
+
this.mt[i] = (((((x & 0xffff0000) >>> 16) * 1812433253) << 16) + (x & 0xffff) * 1812433253) + i;
|
|
22
|
+
this.mt[i] = this.mt[i] >>> 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
twist() {
|
|
27
|
+
for (let i = 0; i < this.N - this.M; i++) {
|
|
28
|
+
const y = (this.mt[i] & this.UPPER_MASK) | (this.mt[i + 1] & this.LOWER_MASK);
|
|
29
|
+
this.mt[i] = this.mt[i + this.M] ^ (y >>> 1) ^ (y & 1 ? this.MATRIX_A : 0);
|
|
30
|
+
}
|
|
31
|
+
for (let i = this.N - this.M; i < this.N - 1; i++) {
|
|
32
|
+
const y = (this.mt[i] & this.UPPER_MASK) | (this.mt[i + 1] & this.LOWER_MASK);
|
|
33
|
+
this.mt[i] = this.mt[i + (this.M - this.N)] ^ (y >>> 1) ^ (y & 1 ? this.MATRIX_A : 0);
|
|
34
|
+
}
|
|
35
|
+
const y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK);
|
|
36
|
+
this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ (y & 1 ? this.MATRIX_A : 0);
|
|
37
|
+
this.mti = 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
next() {
|
|
41
|
+
if (this.mti >= this.N) {
|
|
42
|
+
this.twist();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let y = this.mt[this.mti++];
|
|
46
|
+
y ^= y >>> 11;
|
|
47
|
+
y ^= (y << 7) & 0x9d2c5680;
|
|
48
|
+
y ^= (y << 15) & 0xefc60000;
|
|
49
|
+
y ^= y >>> 18;
|
|
50
|
+
|
|
51
|
+
return y >>> 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
nextInt(max = 2147483647) {
|
|
55
|
+
if (max <= 0) {
|
|
56
|
+
throw new Error('max must be positive');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const limit = Math.floor(0xffffffff / max) * max;
|
|
60
|
+
let val;
|
|
61
|
+
|
|
62
|
+
do {
|
|
63
|
+
val = this.next();
|
|
64
|
+
} while (val >= limit);
|
|
65
|
+
|
|
66
|
+
return val % max;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
nextFloat() {
|
|
70
|
+
const a = this.next() >>> 5;
|
|
71
|
+
const b = this.next() >>> 6;
|
|
72
|
+
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export class PCG64 {
|
|
2
|
+
constructor(seed = 1n, inc = 1n) {
|
|
3
|
+
this.state = 0n;
|
|
4
|
+
this.inc = ((typeof inc === 'number' ? BigInt(inc) : inc) << 1n) | 1n;
|
|
5
|
+
this.step();
|
|
6
|
+
this.state += (typeof seed === 'number' ? BigInt(seed) : seed);
|
|
7
|
+
this.step();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
step() {
|
|
11
|
+
this.state = (this.state * 6364136223846793005n + this.inc) & ((1n << 64n) - 1n);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
next() {
|
|
15
|
+
const oldState = this.state;
|
|
16
|
+
this.step();
|
|
17
|
+
|
|
18
|
+
const xorShifted = ((oldState >> 18n) ^ oldState) >> 27n;
|
|
19
|
+
const rot = oldState >> 59n;
|
|
20
|
+
const result = (xorShifted >> rot) | ((xorShifted << (64n - rot)) & ((1n << 64n) - 1n));
|
|
21
|
+
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
nextInt(max = 2147483647) {
|
|
26
|
+
if (max <= 0) {
|
|
27
|
+
throw new Error('max must be positive');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let val = this.next() & 0x7fffffffffffffffn;
|
|
31
|
+
const limit = (0xffffffffffffffffn / BigInt(max)) * BigInt(max);
|
|
32
|
+
|
|
33
|
+
while (val >= limit) {
|
|
34
|
+
val = this.next() & 0x7fffffffffffffffn;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return Number(val % BigInt(max));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
nextFloat() {
|
|
41
|
+
const val = this.next() & ((1n << 53n) - 1n);
|
|
42
|
+
return Number(val) / 9007199254740992.0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class Splitmix64 {
|
|
2
|
+
constructor(seed = 1) {
|
|
3
|
+
this.state = BigInt(seed);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
next() {
|
|
7
|
+
let z = (this.state += 0x9e3779b97f4a7c15n);
|
|
8
|
+
z = (z ^ (z >> 30n)) * 0xbf58476d1ce4e5b9n;
|
|
9
|
+
z = z ^ (z >> 27n);
|
|
10
|
+
return z;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
nextInt(max = 2147483647) {
|
|
14
|
+
if (max <= 0) {
|
|
15
|
+
throw new Error('max must be positive');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let val = this.next() & 0x7fffffffffffffffn;
|
|
19
|
+
const limit = (0xffffffffffffffffn / BigInt(max)) * BigInt(max);
|
|
20
|
+
|
|
21
|
+
while (val >= limit) {
|
|
22
|
+
val = this.next() & 0x7fffffffffffffffn;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return Number(val % BigInt(max));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
nextFloat() {
|
|
29
|
+
const val = this.next() & ((1n << 53n) - 1n);
|
|
30
|
+
return Number(val) / 9007199254740992.0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class Tent {
|
|
2
|
+
constructor(seed = 0.5, mu = 1.95) {
|
|
3
|
+
this.x = Math.max(0.00001, Math.min(0.99999, seed));
|
|
4
|
+
this.mu = mu;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
next() {
|
|
8
|
+
if (this.x < 0.5) {
|
|
9
|
+
this.x = this.mu * this.x;
|
|
10
|
+
} else {
|
|
11
|
+
this.x = this.mu * (1 - this.x);
|
|
12
|
+
}
|
|
13
|
+
this.x = Math.max(0.00001, Math.min(0.99999, this.x));
|
|
14
|
+
return this.x;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
nextInt(max = 2147483647) {
|
|
18
|
+
return Math.floor(this.next() * max);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
nextFloat() {
|
|
22
|
+
return this.next();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export class Xorshift64 {
|
|
2
|
+
constructor(seed = 1) {
|
|
3
|
+
if (typeof seed !== 'number' && typeof seed !== 'bigint') {
|
|
4
|
+
throw new TypeError('Seed must be a number or bigint');
|
|
5
|
+
}
|
|
6
|
+
this.state = BigInt(seed);
|
|
7
|
+
if (this.state === 0n) this.state = 1n;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
next() {
|
|
11
|
+
let x = this.state;
|
|
12
|
+
x ^= x << 13n;
|
|
13
|
+
x ^= x >> 7n;
|
|
14
|
+
x ^= x << 17n;
|
|
15
|
+
this.state = x;
|
|
16
|
+
return x;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
nextInt(max = 2147483647) {
|
|
20
|
+
if (max <= 0) {
|
|
21
|
+
throw new Error('max must be positive');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let val = this.next() & 0x7fffffffffffffffn;
|
|
25
|
+
const limit = (0xffffffffffffffffn / BigInt(max)) * BigInt(max);
|
|
26
|
+
|
|
27
|
+
while (val >= limit) {
|
|
28
|
+
val = this.next() & 0x7fffffffffffffffn;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Number(val % BigInt(max));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
nextFloat() {
|
|
35
|
+
const val = this.next() & ((1n << 53n) - 1n);
|
|
36
|
+
return Number(val) / 9007199254740992.0;
|
|
37
|
+
}
|
|
38
|
+
}
|