From 69df48f88fe78f647c264c42e7f02413dd55e388 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 17 Dec 2023 21:05:40 +0700 Subject: [PATCH 1/7] fix(number): change expected result for precisions of form 0.000...1 --- src/modules/number/index.ts | 2 +- test/modules/__snapshots__/finance.spec.ts.snap | 16 ++++++++-------- test/modules/__snapshots__/location.spec.ts.snap | 4 ++-- test/modules/number.spec.ts | 11 +++++++++++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 91d987771e0..f17eeb115c4 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -150,7 +150,7 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Precision should be greater than 0.`); } - const factor = 1 / precision; + const factor = Math.pow(10, -Math.log10(precision)); //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n const int = this.int({ min: min * factor, max: max * factor, diff --git a/test/modules/__snapshots__/finance.spec.ts.snap b/test/modules/__snapshots__/finance.spec.ts.snap index 324aad22bf9..b2478f58ea4 100644 --- a/test/modules/__snapshots__/finance.spec.ts.snap +++ b/test/modules/__snapshots__/finance.spec.ts.snap @@ -24,13 +24,13 @@ exports[`finance > 42 > amount > with min and max option 1`] = `"24.98"`; exports[`finance > 42 > amount > with min option 1`] = `"380.79"`; -exports[`finance > 42 > amount > with min, leagcy max, leagcy dec and leagcy symbol 1`] = `"$24.98161"`; +exports[`finance > 42 > amount > with min, leagcy max, leagcy dec and leagcy symbol 1`] = `"$24.98160"`; -exports[`finance > 42 > amount > with min, max and dec option 1`] = `"24.98161"`; +exports[`finance > 42 > amount > with min, max and dec option 1`] = `"24.98160"`; -exports[`finance > 42 > amount > with min, max, dec and symbol option 1`] = `"#24.98161"`; +exports[`finance > 42 > amount > with min, max, dec and symbol option 1`] = `"#24.98160"`; -exports[`finance > 42 > amount > with min, max, dec, symbol and autoFormat option 1`] = `"#24.98161"`; +exports[`finance > 42 > amount > with min, max, dec, symbol and autoFormat option 1`] = `"#24.98160"`; exports[`finance > 42 > bic > noArgs 1`] = `"UYETSCLLG53"`; @@ -244,13 +244,13 @@ exports[`finance > 1337 > amount > with min and max option 1`] = `"20.48"`; exports[`finance > 1337 > amount > with min option 1`] = `"269.40"`; -exports[`finance > 1337 > amount > with min, leagcy max, leagcy dec and leagcy symbol 1`] = `"$20.48099"`; +exports[`finance > 1337 > amount > with min, leagcy max, leagcy dec and leagcy symbol 1`] = `"$20.48098"`; -exports[`finance > 1337 > amount > with min, max and dec option 1`] = `"20.48099"`; +exports[`finance > 1337 > amount > with min, max and dec option 1`] = `"20.48098"`; -exports[`finance > 1337 > amount > with min, max, dec and symbol option 1`] = `"#20.48099"`; +exports[`finance > 1337 > amount > with min, max, dec and symbol option 1`] = `"#20.48098"`; -exports[`finance > 1337 > amount > with min, max, dec, symbol and autoFormat option 1`] = `"#20.48099"`; +exports[`finance > 1337 > amount > with min, max, dec, symbol and autoFormat option 1`] = `"#20.48098"`; exports[`finance > 1337 > bic > noArgs 1`] = `"OEFHLYG18IL"`; diff --git a/test/modules/__snapshots__/location.spec.ts.snap b/test/modules/__snapshots__/location.spec.ts.snap index cfdc45f4b98..b4e2586b184 100644 --- a/test/modules/__snapshots__/location.spec.ts.snap +++ b/test/modules/__snapshots__/location.spec.ts.snap @@ -74,7 +74,7 @@ exports[`location > 42 > longitude > with precision option 1`] = `-45.1655588485 exports[`location > 42 > nearbyGPSCoordinate > near origin 1`] = ` [ - 0.08140632875358443, + 0.08140632875358447, -0.08093642792425726, ] `; @@ -234,7 +234,7 @@ exports[`location > 1211 > longitude > with precision option 1`] = `154.26725534 exports[`location > 1211 > nearbyGPSCoordinate > near origin 1`] = ` [ - -0.02872111236834616, + -0.02872111236834621, 0.05959024752564801, ] `; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 97061d56ffe..35516b33eb4 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -270,6 +270,17 @@ describe('number', () => { } }); + it('provides numbers with an exact precision of 0.00001', () => { + for (let i = 0; i < 100; i++) { + const actual = faker.number.float({ + min: 0.5, + max: 0.99, + precision: 0.00001, + }); + expect(actual).toBe(Number(actual.toFixed(5))); + } + }); + it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( new FakerError('Precision should be greater than 0.') From 94c6fb20dd9063c92ec64c82398de0fd72e93fac Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 17 Dec 2023 21:29:47 +0700 Subject: [PATCH 2/7] only use new algorithm when log10(precision) is integer --- src/modules/number/index.ts | 4 +++- test/modules/number.spec.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index f17eeb115c4..f2f35962f42 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -150,7 +150,9 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Precision should be greater than 0.`); } - const factor = Math.pow(10, -Math.log10(precision)); //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n + const factor = Number.isInteger(Math.log10(precision)) + ? Math.pow(10, -Math.log10(precision)) //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n + : 1 / precision; const int = this.int({ min: min * factor, max: max * factor, diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 35516b33eb4..c9c1dbaeed9 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -259,6 +259,22 @@ describe('number', () => { expect(results).toEqual([0, 0.4, 0.8, 1.2, 1.6]); }); + it('provides numbers with a given precision of 0.2', () => { + const results = [ + ...new Set( + Array.from({ length: 50 }, () => + faker.number.float({ + min: 0, + max: 0.4, + precision: 0.2, + }) + ) + ), + ].sort(); + + expect(results).toEqual([0, 0.2, 0.4]); + }); + it('provides numbers with an exact precision', () => { for (let i = 0; i < 100; i++) { const actual = faker.number.float({ From 2d736f1ca9338d9c0ab8ea50e0b2b01f23c74db1 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Mon, 18 Dec 2023 08:43:43 +0700 Subject: [PATCH 3/7] apply review suggestions --- src/modules/number/index.ts | 5 +++-- test/modules/number.spec.ts | 29 ++++++++++------------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index f2f35962f42..e5f69075e8e 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -150,8 +150,9 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Precision should be greater than 0.`); } - const factor = Number.isInteger(Math.log10(precision)) - ? Math.pow(10, -Math.log10(precision)) //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n + const logPrecision = Math.log10(precision); + const factor = Number.isInteger(logPrecision) + ? Math.pow(10, -logPrecision) //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n : 1 / precision; const int = this.int({ min: min * factor, diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index c9c1dbaeed9..71b9fe9d4c9 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -275,25 +275,16 @@ describe('number', () => { expect(results).toEqual([0, 0.2, 0.4]); }); - it('provides numbers with an exact precision', () => { - for (let i = 0; i < 100; i++) { - const actual = faker.number.float({ - min: 0.5, - max: 0.99, - precision: 0.01, - }); - expect(actual).toBe(Number(actual.toFixed(2))); - } - }); - - it('provides numbers with an exact precision of 0.00001', () => { - for (let i = 0; i < 100; i++) { - const actual = faker.number.float({ - min: 0.5, - max: 0.99, - precision: 0.00001, - }); - expect(actual).toBe(Number(actual.toFixed(5))); + it('provides numbers with an exact precision of 10^-x for x=1 to 18', () => { + for (let factor = 1; factor <= 18; factor++) { + for (let i = 0; i < 100; i++) { + const actual = faker.number.float({ + min: 0.5, + max: 0.99, + precision: Math.pow(10, -factor), + }); + expect(actual).toBe(Number(actual.toFixed(factor))); + } } }); From fce40457ee0974624711d3274e890cd6345553d6 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Mon, 18 Dec 2023 17:15:28 +0700 Subject: [PATCH 4/7] change to use it.each --- test/modules/number.spec.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 71b9fe9d4c9..989ec3de2c0 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -275,18 +275,20 @@ describe('number', () => { expect(results).toEqual([0, 0.2, 0.4]); }); - it('provides numbers with an exact precision of 10^-x for x=1 to 18', () => { - for (let factor = 1; factor <= 18; factor++) { + const exponents = Array.from({ length: 18 }, (_, i) => i + 1); + it.each(exponents)( + `provides numbers with an exact precision of 10^-%d`, + (exponent) => { for (let i = 0; i < 100; i++) { const actual = faker.number.float({ min: 0.5, max: 0.99, - precision: Math.pow(10, -factor), + precision: Math.pow(10, -exponent), }); - expect(actual).toBe(Number(actual.toFixed(factor))); + expect(actual).toBe(Number(actual.toFixed(exponent))); } } - }); + ); it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( From 958026af12b8709ecd1442aa1cba5fd8f201ed9e Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Wed, 20 Dec 2023 11:01:32 +0700 Subject: [PATCH 5/7] update comment and use ** --- src/modules/number/index.ts | 8 +++++--- test/modules/number.spec.ts | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index e5f69075e8e..4becb3480d4 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -151,9 +151,11 @@ export class NumberModule extends SimpleModuleBase { } const logPrecision = Math.log10(precision); - const factor = Number.isInteger(logPrecision) - ? Math.pow(10, -logPrecision) //mathematically this is the same as 1/precision, however it helpfully gives integer values for all precisions of the form 10^-n - : 1 / precision; + // Workaround to get integer values for the inverse of all precisions of the form 10^-n + const factor = + precision < 1 && Number.isInteger(logPrecision) + ? 10 ** -logPrecision + : 1 / precision; const int = this.int({ min: min * factor, max: max * factor, diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 989ec3de2c0..3032391a83d 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -275,8 +275,7 @@ describe('number', () => { expect(results).toEqual([0, 0.2, 0.4]); }); - const exponents = Array.from({ length: 18 }, (_, i) => i + 1); - it.each(exponents)( + it.each(Array.from({ length: 18 }, (_, i) => i + 1))( `provides numbers with an exact precision of 10^-%d`, (exponent) => { for (let i = 0; i < 100; i++) { @@ -289,6 +288,19 @@ describe('number', () => { } } ); + it.each(Array.from({ length: 18 }, (_, i) => i))( + `provides numbers with an exact precision of 10^%d`, + (exponent) => { + for (let i = 0; i < 100; i++) { + const actual = faker.number.float({ + min: 1, + max: Math.pow(10, exponent + 1), + precision: Math.pow(10, exponent), + }); + expect(Number.isInteger(actual)).toBe(true); + } + } + ); it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( From 4a05807a611ba95c4e85628748e6642cfe9b2715 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Wed, 20 Dec 2023 11:06:56 +0700 Subject: [PATCH 6/7] rv test change --- test/modules/number.spec.ts | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 3032391a83d..989ec3de2c0 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -275,7 +275,8 @@ describe('number', () => { expect(results).toEqual([0, 0.2, 0.4]); }); - it.each(Array.from({ length: 18 }, (_, i) => i + 1))( + const exponents = Array.from({ length: 18 }, (_, i) => i + 1); + it.each(exponents)( `provides numbers with an exact precision of 10^-%d`, (exponent) => { for (let i = 0; i < 100; i++) { @@ -288,19 +289,6 @@ describe('number', () => { } } ); - it.each(Array.from({ length: 18 }, (_, i) => i))( - `provides numbers with an exact precision of 10^%d`, - (exponent) => { - for (let i = 0; i < 100; i++) { - const actual = faker.number.float({ - min: 1, - max: Math.pow(10, exponent + 1), - precision: Math.pow(10, exponent), - }); - expect(Number.isInteger(actual)).toBe(true); - } - } - ); it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( From 54c5526474956683957cfe2a655110361d656920 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Wed, 20 Dec 2023 20:39:23 +0700 Subject: [PATCH 7/7] use times and ** in test --- test/modules/number.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 989ec3de2c0..81a1e992c72 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'; import { faker, FakerError, SimpleFaker } from '../../src'; import { MERSENNE_MAX_VALUE } from '../internal/mersenne-test-utils'; import { seededTests } from '../support/seeded-runs'; +import { times } from './../support/times'; describe('number', () => { seededTests(faker, 'number', (t) => { @@ -275,15 +276,14 @@ describe('number', () => { expect(results).toEqual([0, 0.2, 0.4]); }); - const exponents = Array.from({ length: 18 }, (_, i) => i + 1); - it.each(exponents)( + it.each(times(18))( `provides numbers with an exact precision of 10^-%d`, (exponent) => { for (let i = 0; i < 100; i++) { const actual = faker.number.float({ min: 0.5, max: 0.99, - precision: Math.pow(10, -exponent), + precision: 10 ** -exponent, }); expect(actual).toBe(Number(actual.toFixed(exponent))); }