Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34e62e3
feat(number): add exponentialDistribution function
ST-DDT Jan 18, 2025
d3236f4
chore: simplify tables
ST-DDT Jan 19, 2025
294fa79
feat(number): introduce distributor functions
ST-DDT Feb 17, 2025
b56abb7
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Feb 17, 2025
2d02ceb
docs: fix missing param tags
ST-DDT Feb 17, 2025
9e60210
docs: add distributors api docs
ST-DDT Feb 17, 2025
a769fb0
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Mar 6, 2025
f16831a
Merge branch 'next' into feat/number/exponentional-distribution
xDivisionByZerox Jan 9, 2026
4958bb5
docs: minor rephrasing for more natural language
xDivisionByZerox Jan 9, 2026
b71f3a9
docs: update @since tags to 10.3.0
xDivisionByZerox Jan 9, 2026
cf5ad5b
Merge remote-tracking branch 'origin/next' into feat/number/exponenti…
xDivisionByZerox Feb 26, 2026
1c1fd44
docs: fix typo in jsdoc
xDivisionByZerox Feb 26, 2026
127f1b6
docs: update since tags to 10.4.0
xDivisionByZerox Feb 26, 2026
9e7c846
chore: remove duplicated markdown api doc file since it has been moved
xDivisionByZerox Feb 26, 2026
577fb9b
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Apr 5, 2026
dc40f79
chore: fix merge issue
ST-DDT Apr 5, 2026
f00cc78
chore: bump since
ST-DDT Apr 5, 2026
bc50745
docs: refreshable distributor examples
ST-DDT Apr 5, 2026
b66c3e0
chore: merge code paths
ST-DDT Apr 5, 2026
5d3df1f
chore: simplify
ST-DDT Apr 5, 2026
6c544ec
chore: edit after review
ST-DDT Apr 5, 2026
f44ad4f
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Apr 8, 2026
cec8d5b
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Apr 14, 2026
4090581
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Apr 15, 2026
5382436
chore: remove redundant jsdocs
ST-DDT Apr 15, 2026
b6d164d
chore: add tests
ST-DDT Apr 15, 2026
3cb5531
Merge branch 'next' into feat/number/exponentional-distribution
ST-DDT Apr 17, 2026
2311597
test: simplify number module tests
ST-DDT Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions scripts/apidocs/utils/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@ const htmlSanitizeOptions: sanitizeHtml.IOptions = {
'span',
'strong',
'ul',
'table',
'thead',
'tbody',
'tr',
'th',
'td',
],
allowedAttributes: {
a: ['href', 'target', 'rel'],
button: ['class', 'title'],
div: ['class'],
pre: ['class', 'v-pre', 'tabindex'],
span: ['class', 'style'],
table: ['tabindex'],
th: ['style'],
td: ['style'],
},
selfClosing: [],
};
Expand Down
161 changes: 161 additions & 0 deletions src/modules/number/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,4 +534,165 @@ export class NumberModule extends SimpleModuleBase {

return result;
}

/**
* Generates a random number between `min` and `max` using an exponential distribution.
Comment thread
matthewmayer marked this conversation as resolved.
Outdated
* The lower bound is inclusive, but the upper bound is exclusive.
*
* The following table shows the rough distribution of values generated using `Math.floor(exponentialDistribution({ min: 0, max: 10, base: x }))`:
*
* | Value | Base 0.1 | Base 0.5 | Base 1 | Base 2 | Base 10 |
* | :---: | -------: | -------: | -----: | -----: | ------: |
* | 0 | 4.1% | 7.4% | 10.0% | 13.8% | 27.8% |
* | 1 | 4.5% | 7.8% | 10.0% | 12.5% | 16.9% |
* | 2 | 5.0% | 8.2% | 10.0% | 11.5% | 12.1% |
* | 3 | 5.7% | 8.7% | 10.0% | 10.7% | 9.4% |
* | 4 | 6.6% | 9.3% | 10.0% | 10.0% | 7.8% |
* | 5 | 7.8% | 9.9% | 10.0% | 9.3% | 6.6% |
* | 6 | 9.4% | 10.7% | 10.0% | 8.8% | 5.7% |
* | 7 | 12.1% | 11.5% | 10.0% | 8.2% | 5.0% |
* | 8 | 16.9% | 12.6% | 10.0% | 7.8% | 4.5% |
* | 9 | 27.9% | 13.8% | 10.0% | 7.5% | 4.1% |
Comment thread
ST-DDT marked this conversation as resolved.
Outdated
*
* The following table shows the rough distribution of values generated using `Math.floor(exponentialDistribution({ min: 0, max: 10, bias: x }))`:
*
* | Value | Bias -9 | Bias -1 | Bias 0 | Bias 1 | Bias 9 |
* | :---: | ------: | ------: | -----: | -----: | -----: |
* | 0 | 27.9% | 13.7% | 10.0% | 7.4% | 4.1% |
* | 1 | 16.9% | 12.5% | 10.0% | 7.8% | 4.5% |
* | 2 | 12.1% | 11.6% | 10.0% | 8.3% | 5.1% |
* | 3 | 9.5% | 10.7% | 10.0% | 8.8% | 5.7% |
* | 4 | 7.8% | 10.0% | 10.0% | 9.3% | 6.6% |
* | 5 | 6.6% | 9.3% | 10.0% | 9.9% | 7.7% |
* | 6 | 5.7% | 8.8% | 10.0% | 10.7% | 9.5% |
* | 7 | 5.0% | 8.2% | 10.0% | 11.5% | 12.1% |
* | 8 | 4.5% | 7.8% | 10.0% | 12.6% | 16.8% |
* | 9 | 4.1% | 7.4% | 10.0% | 13.7% | 27.9% |
*
* @param options The options for generating the number.
* @param options.min The minimum value to generate (inclusive). Defaults to `0`.
* @param options.max The maximum value to generate (exclusive). Defaults to `1`.
* @param options.base The base of the exponential distribution. Should be greater than `0`. Defaults to `2`.
*
* The higher/more above `1` the `base`, the more likely the number will be closer to the minimum value.
* The lower/closer to zero the base, the more likely the number will be closer to the maximum value.
* Values of `1` will generate a uniform distribution.
* The following table shows the rough distribution of values generated using `Math.floor(exponentialDistribution({ min: 0, max: 10, base: x }))`:
*
* | Value | Base 0.1 | Base 0.5 | Base 1 | Base 2 | Base 10 |
* | :---: | -------: | -------: | -----: | -----: | ------: |
* | 0 | 4.1% | 7.4% | 10.0% | 13.8% | 27.8% |
* | 1 | 4.5% | 7.8% | 10.0% | 12.5% | 16.9% |
* | 2 | 5.0% | 8.2% | 10.0% | 11.5% | 12.1% |
* | 3 | 5.7% | 8.7% | 10.0% | 10.7% | 9.4% |
* | 4 | 6.6% | 9.3% | 10.0% | 10.0% | 7.8% |
* | 5 | 7.8% | 9.9% | 10.0% | 9.3% | 6.6% |
* | 6 | 9.4% | 10.7% | 10.0% | 8.8% | 5.7% |
* | 7 | 12.1% | 11.5% | 10.0% | 8.2% | 5.0% |
* | 8 | 16.9% | 12.6% | 10.0% | 7.8% | 4.5% |
* | 9 | 27.9% | 13.8% | 10.0% | 7.5% | 4.1% |
*
* Can alternatively be configured using the `bias` option. `base` takes precedence over `bias`.
* @param options.bias An alternative way to specify the `base`. Also accepts values below zero.
*
* The higher/more positive the `bias`, the more likely the number will be closer to the maximum value.
* The lower/more negative the `bias`, the more likely the number will be closer to the minimum value.
* Values of 0 will generate a uniform distribution.
*
* The following table shows the rough distribution of values generated using `Math.floor(exponentialDistribution({ min: 0, max: 10, bias: x }))`:
*
* | Value | Bias -9 | Bias -1 | Bias 0 | Bias 1 | Bias 9 |
* | :---: | ------: | ------: | -----: | -----: | -----: |
* | 0 | 27.9% | 13.7% | 10.0% | 7.4% | 4.1% |
* | 1 | 16.9% | 12.5% | 10.0% | 7.8% | 4.5% |
* | 2 | 12.1% | 11.6% | 10.0% | 8.3% | 5.1% |
* | 3 | 9.5% | 10.7% | 10.0% | 8.8% | 5.7% |
* | 4 | 7.8% | 10.0% | 10.0% | 9.3% | 6.6% |
* | 5 | 6.6% | 9.3% | 10.0% | 9.9% | 7.7% |
* | 6 | 5.7% | 8.8% | 10.0% | 10.7% | 9.5% |
* | 7 | 5.0% | 8.2% | 10.0% | 11.5% | 12.1% |
* | 8 | 4.5% | 7.8% | 10.0% | 12.6% | 16.8% |
* | 9 | 4.1% | 7.4% | 10.0% | 13.7% | 27.9% |
*
* This option is ignored if `base` is specified.
*
* Defaults to `-1`.
*
* @throws If `base` is less than or equal to `0`.
* @throws If `max` is less than `min`.
*
* @example
* faker.number.exponentialDistribution() // 0.41928964795957224
* faker.number.exponentialDistribution(10) // 1.656598169056771
* faker.number.exponentialDistribution({ min: 10, max: 100 }) // 88.7273250669911
* faker.number.exponentialDistribution({ min: 0, max: 100, base: 10 }) // 6.9442760672808745
* faker.number.exponentialDistribution({ min: 0, max: 100, bias: 10 }) // 67.03715679154617
Comment thread
ST-DDT marked this conversation as resolved.
Outdated
*
* @since 9.5.0
*/
exponentialDistribution(
Comment thread
ST-DDT marked this conversation as resolved.
Outdated
options:
| number
| {
/**
* The minimum value to generate (inclusive).
*
* @default 0
*/
min?: number;
/**
* The maximum value to generate (exclusive).
*
* @default 1
*/
max?: number;
/**
* The base of the exponential distribution. Should be greater than 0. Defaults to `2`.
* The higher/more above `1` the `base`, the more likely the number will be closer to the minimum value.
* The lower/closer to zero the `base`, the more likely the number will be closer to the maximum value.
* Values of `1` will generate a uniform distribution.
* Can alternatively be configured using the `bias` option. `base` takes precedence over `bias`.
*
* @default 2
*/
base?: number;
/**
* An alternative way to specify the `base`. Also accepts values below zero.
* The higher/more positive the `bias`, the more likely the number will be closer to the maximum value.
* The lower/more negative the `bias`, the more likely the number will be closer to the minimum value.
* Values of `0` will generate a uniform distribution.
* This option is ignored if `base` is specified.
*
* @default -1
*/
bias?: number;
} = {}
): number {
if (typeof options === 'number') {
options = { min: 0, max: options };
}

const {
min = 0,
max = 1,
bias = -1,
base = bias <= 0 ? -bias + 1 : 1 / (bias + 1),
} = options;

if (base === 1) {
return this.faker.number.float({ min, max });
} else if (base <= 0) {
throw new FakerError('Base should be greater than 0.');
}

if (max === min) {
return min;
} else if (max < min) {
throw new FakerError(`Max ${max} should be greater than min ${min}.`);
}

const exponent = this.faker.number.float();
const factor = (base ** exponent - 1) / (base - 1);
return min + (max - min) * factor;
}
}
42 changes: 42 additions & 0 deletions test/modules/__snapshots__/number.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ exports[`number > 42 > binary > with options 1`] = `"100"`;

exports[`number > 42 > binary > with value 1`] = `"0"`;

exports[`number > 42 > exponentialDistribution > noArgs 1`] = `0.29642623304954707`;

exports[`number > 42 > exponentialDistribution > with high base 1`] = `0.15209599448489752`;

exports[`number > 42 > exponentialDistribution > with high bias 1`] = `0.6420630212280508`;

exports[`number > 42 > exponentialDistribution > with low base 1`] = `0.6420630212280508`;

exports[`number > 42 > exponentialDistribution > with low bias 1`] = `0.15209599448489752`;

exports[`number > 42 > exponentialDistribution > with max 1`] = `2.9642623304954707`;

exports[`number > 42 > exponentialDistribution > with min and max 1`] = `36.67836097445924`;

exports[`number > 42 > float > with max 1`] = `25.84326820046801`;

exports[`number > 42 > float > with min 1`] = `-25.89477488956341`;
Expand Down Expand Up @@ -84,6 +98,20 @@ exports[`number > 1211 > binary > with options 1`] = `"1010"`;

exports[`number > 1211 > binary > with value 1`] = `"1"`;

exports[`number > 1211 > exponentialDistribution > noArgs 1`] = `0.9033226590337899`;

exports[`number > 1211 > exponentialDistribution > with high base 1`] = `0.8313808279511881`;

exports[`number > 1211 > exponentialDistribution > with high bias 1`] = `0.9801213540567579`;

exports[`number > 1211 > exponentialDistribution > with low base 1`] = `0.9801213540567579`;

exports[`number > 1211 > exponentialDistribution > with low bias 1`] = `0.8313808279511881`;

exports[`number > 1211 > exponentialDistribution > with max 1`] = `9.0332265903379`;

exports[`number > 1211 > exponentialDistribution > with min and max 1`] = `91.29903931304109`;

exports[`number > 1211 > float > with max 1`] = `64.06789061927832`;

exports[`number > 1211 > float > with min 1`] = `-2.0736333821888806`;
Expand Down Expand Up @@ -148,6 +176,20 @@ exports[`number > 1337 > binary > with options 1`] = `"10"`;

exports[`number > 1337 > binary > with value 1`] = `"0"`;

exports[`number > 1337 > exponentialDistribution > noArgs 1`] = `0.1991604233570674`;

exports[`number > 1337 > exponentialDistribution > with high base 1`] = `0.092022676113987`;

exports[`number > 1337 > exponentialDistribution > with high bias 1`] = `0.5033501285097729`;

exports[`number > 1337 > exponentialDistribution > with low base 1`] = `0.5033501285097729`;

exports[`number > 1337 > exponentialDistribution > with low bias 1`] = `0.092022676113987`;

exports[`number > 1337 > exponentialDistribution > with max 1`] = `1.991604233570674`;

exports[`number > 1337 > exponentialDistribution > with min and max 1`] = `27.924438102136065`;

exports[`number > 1337 > float > with max 1`] = `18.079702576075135`;

exports[`number > 1337 > float > with min 1`] = `-30.73293897432999`;
Expand Down
112 changes: 112 additions & 0 deletions test/modules/number.spec.ts
Comment thread
ST-DDT marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ describe('number', () => {
.it('with max as 3999', { max: 3999 })
.it('with min and max', { min: 100, max: 502 });
});

t.describe('exponentialDistribution', (t) => {
t.it('noArgs')
.it('with max', 10)
.it('with low base', { base: 0.1 })
.it('with high base', { base: 10 })
.it('with low bias', { bias: -9 })
.it('with high bias', { bias: 9 })
.it('with min and max', { min: 10, max: 100 });
});
});

describe(`random seeded tests for seed ${faker.seed()}`, () => {
Expand Down Expand Up @@ -697,6 +707,108 @@ describe('number', () => {
}).toThrow(new FakerError('Max 100 should be greater than min 500.'));
});
});

describe('exponentialDistribution', () => {
it('should generate a number between 0 and 1 by default', () => {
const actual = faker.number.exponentialDistribution();
expect(actual).toBeTypeOf('number');
expect(actual).toBeGreaterThanOrEqual(0);
expect(actual).toBeLessThan(1);
});

it('should generate a number between 0 and 10', () => {
const actual = faker.number.exponentialDistribution(10);
expect(actual).toBeTypeOf('number');
expect(actual).toBeGreaterThanOrEqual(0);
expect(actual).toBeLessThan(10);
});

it('should generate a number between 10 and 100', () => {
const actual = faker.number.exponentialDistribution({
min: 10,
max: 100,
});
expect(actual).toBeTypeOf('number');
expect(actual).toBeGreaterThanOrEqual(10);
expect(actual).toBeLessThan(100);
});

it('should generate a number with low base', () => {
const results = Array.from({ length: 10 }, (_, i) => i);
for (let i = 0; i < 1000; i++) {
results[
Math.floor(
faker.number.exponentialDistribution({ max: 10, base: 0.1 })
)
]++;
}

expect(results[0]).toBeLessThan(75);
expect(results[9]).toBeGreaterThan(200);
});

it('should generate a number with high base', () => {
const results = Array.from({ length: 10 }, (_, i) => i);
for (let i = 0; i < 1000; i++) {
results[
Math.floor(
faker.number.exponentialDistribution({ max: 10, base: 10 })
)
]++;
}

expect(results[0]).toBeGreaterThan(200);
expect(results[9]).toBeLessThan(75);
});

it('should generate a number with low bias', () => {
const results = Array.from({ length: 10 }, (_, i) => i);
for (let i = 0; i < 1000; i++) {
results[
Math.floor(
faker.number.exponentialDistribution({ max: 10, bias: -9 })
)
]++;
}

expect(results[0]).toBeGreaterThan(200);
expect(results[9]).toBeLessThan(75);
});

it('should generate a number with high bias', () => {
const results = Array.from({ length: 10 }, (_, i) => i);
for (let i = 0; i < 1000; i++) {
results[
Math.floor(
faker.number.exponentialDistribution({ max: 10, bias: 9 })
)
]++;
}

expect(results[0]).toBeLessThan(75);
expect(results[9]).toBeGreaterThan(200);
});
});

it('should throw when min > max', () => {
const min = 10;
const max = 9;

expect(() => {
faker.number.exponentialDistribution({ min, max });
}).toThrow(
new FakerError(`Max ${max} should be greater than min ${min}.`)
);
});

it('should throw when base is less than or equal to 0', () => {
expect(() => {
faker.number.exponentialDistribution({ base: 0 });
}).toThrow(new FakerError('Base should be greater than 0.'));
expect(() => {
faker.number.exponentialDistribution({ base: -1 });
}).toThrow(new FakerError('Base should be greater than 0.'));
});
});

describe('value range tests', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ exports[`check docs completeness > all modules and methods are present 1`] = `
[
"bigInt",
"binary",
"exponentialDistribution",
"float",
"hex",
"int",
Expand Down