Repository: dubzzz/fast-check
Pull request #1709 (2021-04-08 18:04:36)

🚚 Move integer arbitraries into /arbitrary
<!-- Why is this PR for? -->
<!-- Describe the reason why you opened this PR or give a link towards the associated issue. -->

## In a nutshell

Adopting new file layout for #387

❌ New feature
❌ Fix an issue
❌ Documentation improvement
✔️ Other: *moving code*

(✔️: yes, ❌: no)

## Potential impacts

No impact is expected as IDE fail to import the right paths with auto-imports different from root.
Non-root import changed for `integer`, `nat`, `maxSafeNat`, `maxSafeInteger`


codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/dubzzz/fast-check/pr/1709/builds/117678) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e235b0fdbaa4bd65fec53b291741f7f2d0ae3ad0:

|Sandbox| Source |
|--|--|
|[Vanilla](https://codesandbox.io/s/vanilla-nhnse)| Configuration |
|[fast-check-examples](https://codesandbox.io/s/fast-check-examples-0muqv)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=h1) Report
> Merging [#1709](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=desc) (e235b0f) into [main](https://codecov.io/gh/dubzzz/fast-check/commit/ce6a3c56fa9bca3a0fb68c5c58ae7dab342c5e09?el=desc) (ce6a3c5) will **decrease** coverage by `0.46%`.
> The diff coverage is `95.79%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1709/graphs/tree.svg?width=650&height=150&src=pr&token=fRi2fJN730)](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             main    #1709      +/-   ##
==========================================
- Coverage   96.95%   96.49%   -0.47%     
==========================================
  Files          98      102       +4     
  Lines        3519     3564      +45     
  Branches      697      705       +8     
==========================================
+ Hits         3412     3439      +27     
- Misses        103      121      +18     
  Partials        4        4              
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `96.49% <95.79%> (-0.47%)` | :arrow_down: |
| unit-tests-10.x-Linux | `96.49% <95.79%> (-0.47%)` | :arrow_down: |
| unit-tests-12.x-Linux | `?` | |
| unit-tests-14.x-Linux | `?` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/arbitrary/\_internals/IntegerArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9faW50ZXJuYWxzL0ludGVnZXJBcmJpdHJhcnkudHM=) | `89.58% <89.58%> (ø)` | |
| [...c/arbitrary/\_internals/helpers/BiasNumericRange.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9faW50ZXJuYWxzL2hlbHBlcnMvQmlhc051bWVyaWNSYW5nZS50cw==) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/\_internals/helpers/ShrinkInteger.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9faW50ZXJuYWxzL2hlbHBlcnMvU2hyaW5rSW50ZWdlci50cw==) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/integer.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9pbnRlZ2VyLnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/maxSafeInteger.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9tYXhTYWZlSW50ZWdlci50cw==) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/maxSafeNat.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9tYXhTYWZlTmF0LnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/nat.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2FyYml0cmFyeS9uYXQudHM=) | `100.00% <100.00%> (ø)` | |
| [src/check/arbitrary/ArrayArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9BcnJheUFyYml0cmFyeS50cw==) | `85.96% <100.00%> (ø)` | |
| [src/check/arbitrary/BigIntArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9CaWdJbnRBcmJpdHJhcnkudHM=) | `92.59% <100.00%> (ø)` | |
| [src/check/arbitrary/BooleanArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9Cb29sZWFuQXJiaXRyYXJ5LnRz) | `100.00% <100.00%> (ø)` | |
| ... and [21 more](https://codecov.io/gh/dubzzz/fast-check/pull/1709/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=footer). Last update [ce6a3c5...e235b0f](https://codecov.io/gh/dubzzz/fast-check/pull/1709?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/arbitrary/_internals/IntegerArbitrary.ts b/src/arbitrary/_internals/IntegerArbitrary.ts
new file mode 100644
index 00000000..b7cb8282
--- /dev/null
+++ b/src/arbitrary/_internals/IntegerArbitrary.ts
@@ -0,0 +1,95 @@
+import { NextArbitrary } from '../../check/arbitrary/definition/NextArbitrary';
+import { NextValue } from '../../check/arbitrary/definition/NextValue';
+import { Random } from '../../random/generator/Random';
+import { Stream } from '../../stream/Stream';
+import { integerLogLike, biasNumericRange } from './helpers/BiasNumericRange';
+import { shrinkInteger } from './helpers/ShrinkInteger';
+
+/** @internal */
+export class IntegerArbitrary extends NextArbitrary<number> {
+  static MIN_INT: number = 0x80000000 | 0;
+  static MAX_INT: number = 0x7fffffff | 0;
+
+  constructor(readonly min: number, readonly max: number) {
+    super();
+  }
+
+  generate(mrng: Random, biasFactor: number | undefined): NextValue<number> {
+    const range = this.computeGenerateRange(mrng, biasFactor);
+    return new NextValue(mrng.nextInt(range.min, range.max), undefined);
+  }
+
+  canGenerate(value: unknown): value is number {
+    return typeof value === 'number' && Number.isInteger(value) && this.min <= value && value <= this.max;
+  }
+
+  shrink(current: number, context?: unknown): Stream<NextValue<number>> {
+    if (current === 0) {
+      return Stream.nil();
+    }
+    if (!IntegerArbitrary.isValidContext(current, context)) {
+      // No context:
+      //   Take default target and shrink towards it
+      //   Try the target on first try
+      const target = this.defaultTarget();
+      return shrinkInteger(current, target, true);
+    }
+    if (this.isLastChanceTry(current, context)) {
+      // Last chance try...
+      // context is set to undefined, so that shrink will restart
+      // without any assumptions in case our try find yet another bug
+      return Stream.of(new NextValue(context, undefined));
+    }
+    // Normal shrink process
+    return shrinkInteger(current, context, false);
+  }
+
+  defaultTarget(): number {
+    // min <= 0 && max >= 0   => shrink towards zero
+    if (this.min <= 0 && this.max >= 0) {
+      return 0;
+    }
+    // min < 0                => shrink towards max (closer to zero)
+    // otherwise              => shrink towards min (closer to zero)
+    return this.min < 0 ? this.max : this.min;
+  }
+
+  private computeGenerateRange(mrng: Random, biasFactor: number | undefined): { min: number; max: number } {
+    if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) {
+      return { min: this.min, max: this.max };
+    }
+    const ranges = biasNumericRange(this.min, this.max, integerLogLike);
+    if (ranges.length === 1) {
+      return ranges[0];
+    }
+    const id = mrng.nextInt(-2 * (ranges.length - 1), ranges.length - 2); // 1st range has the highest priority
+    return id < 0 ? ranges[0] : ranges[id + 1];
+  }
+
+  private isLastChanceTry(current: number, context: number): boolean {
+    // If true...
+    // We already reached what we thought to be the minimal failing value.
+    // But in-between other values may have shrunk (values coming from other arbitraries).
+    // In order to check if they impacted us, we just try to move very close to our current value.
+    // It is not ideal but it can help restart a shrinking process that stopped too early.
+    if (current > 0) return current === context + 1 && current > this.min;
+    if (current < 0) return current === context - 1 && current < this.max;
+    return false;
+  }
+
+  private static isValidContext(current: number, context?: unknown): context is number {
+    // Context contains a value between zero and current that is known to be
+    // the closer to zero passing value*.
+    // *More precisely: our shrinker will not try something closer to zero
+    if (context === undefined) {
+      return false;
+    }
+    if (typeof context !== 'number') {
+      throw new Error(`Invalid context type passed to IntegerArbitrary (#1)`);
+    }
+    if (context !== 0 && Math.sign(current) !== Math.sign(context)) {
+      throw new Error(`Invalid context value passed to IntegerArbitrary (#2)`);
+    }
+    return true;
+  }
+}
diff --git a/src/check/arbitrary/helpers/BiasNumeric.ts b/src/arbitrary/_internals/helpers/BiasNumericRange.ts
similarity index 76%
rename from src/check/arbitrary/helpers/BiasNumeric.ts
rename to src/arbitrary/_internals/helpers/BiasNumericRange.ts
index 2ead4d83..7a5d1e12 100644
--- a/src/check/arbitrary/helpers/BiasNumeric.ts
+++ b/src/arbitrary/_internals/helpers/BiasNumericRange.ts
@@ -1,15 +1,18 @@
 /** @internal */
-function retrieveBiasRangesForNumeric(
-  min: number,
-  max: number,
-  logLike: (n: number) => number
-): { min: number; max: number }[];
-function retrieveBiasRangesForNumeric(
-  min: bigint,
-  max: bigint,
-  logLike: (n: bigint) => bigint
-): { min: bigint; max: bigint }[];
-function retrieveBiasRangesForNumeric<NType extends number | bigint>(
+export function integerLogLike(v: number): number {
+  return Math.floor(Math.log(v) / Math.log(2));
+}
+
+/** @internal */
+export function bigIntLogLike(v: bigint): bigint {
+  if (v === BigInt(0)) return BigInt(0);
+  return BigInt(v.toString().length);
+}
+
+/** @internal */
+function biasNumericRange(min: number, max: number, logLike: (n: number) => number): { min: number; max: number }[];
+function biasNumericRange(min: bigint, max: bigint, logLike: (n: bigint) => bigint): { min: bigint; max: bigint }[];
+function biasNumericRange<NType extends number | bigint>(
   min: NType,
   max: NType,
   logLike: (n: NType) => NType
@@ -37,15 +40,4 @@ function retrieveBiasRangesForNumeric<NType extends number | bigint>(
     : [arbCloseToMin, arbCloseToMax]; // min is closer to zero
 }
 
-export { retrieveBiasRangesForNumeric };
-
-/** @internal */
-export function integerLogLike(v: number): number {
-  return Math.floor(Math.log(v) / Math.log(2));
-}
-
-/** @internal */
-export function bigIntLogLike(v: bigint): bigint {
-  if (v === BigInt(0)) return BigInt(0);
-  return BigInt(v.toString().length);
-}
+export { biasNumericRange };
diff --git a/src/check/arbitrary/helpers/ShrinkInteger.ts b/src/arbitrary/_internals/helpers/ShrinkInteger.ts
similarity index 95%
rename from src/check/arbitrary/helpers/ShrinkInteger.ts
rename to src/arbitrary/_internals/helpers/ShrinkInteger.ts
index d96788bd..90be120f 100644
--- a/src/check/arbitrary/helpers/ShrinkInteger.ts
+++ b/src/arbitrary/_internals/helpers/ShrinkInteger.ts
@@ -1,5 +1,5 @@
+import { NextValue } from '../../../check/arbitrary/definition/NextValue';
 import { Stream, stream } from '../../../stream/Stream';
-import { NextValue } from '../definition/NextValue';
 
 /** @internal */
 function halvePosInteger(n: number): number {
diff --git a/src/arbitrary/integer.ts b/src/arbitrary/integer.ts
new file mode 100644
index 00000000..5c7c3991
--- /dev/null
+++ b/src/arbitrary/integer.ts
@@ -0,0 +1,102 @@
+import { ArbitraryWithContextualShrink as _IntegerMock } from '../check/arbitrary/definition/ArbitraryWithContextualShrink';
+import { convertFromNextWithShrunkOnce } from '../check/arbitrary/definition/Converters';
+import { IntegerArbitrary } from './_internals/IntegerArbitrary';
+
+/**
+ * Constraints to be applied on {@link integer}
+ * @remarks Since 2.6.0
+ * @public
+ */
+export interface IntegerConstraints {
+  /**
+   * Lower bound for the generated integers (included)
+   * @defaultValue -0x80000000
+   * @remarks Since 2.6.0
+   */
+  min?: number;
+  /**
+   * Upper bound for the generated integers (included)
+   * @defaultValue 0x7fffffff
+   * @remarks Since 2.6.0
+   */
+  max?: number;
+}
+
+/**
+ * Build fully set IntegerConstraints from a partial data
+ * @internal
+ */
+function buildCompleteIntegerConstraints(constraints: IntegerConstraints): Required<IntegerConstraints> {
+  const min = constraints.min !== undefined ? constraints.min : IntegerArbitrary.MIN_INT;
+  const max = constraints.max !== undefined ? constraints.max : IntegerArbitrary.MAX_INT;
+  return { min, max };
+}
+
+/**
+ * Extract constraints from args received by integer
+ * @internal
+ */
+function extractIntegerConstraints(args: [] | [number] | [number, number] | [IntegerConstraints]): IntegerConstraints {
+  if (args[0] === undefined) {
+    // integer()
+    return {};
+  } // args.length > 0
+
+  if (args[1] === undefined) {
+    const sargs = args as typeof args & [unknown]; // exactly 1 arg specified
+    if (typeof sargs[0] === 'number') return { max: sargs[0] }; // integer(max)
+    return sargs[0]; // integer(constraints)
+  } // args.length > 1
+
+  const sargs = args as typeof args & [unknown, unknown];
+  return { min: sargs[0], max: sargs[1] }; // integer(min, max)
+}
+
+/**
+ * For integers between -2147483648 (included) and 2147483647 (included)
+ * @remarks Since 0.0.1
+ * @public
+ */
+function integer(): _IntegerMock<number>;
+/**
+ * For integers between -2147483648 (included) and max (included)
+ *
+ * @param max - Upper bound for the generated integers (eg.: 2147483647, Number.MAX_SAFE_INTEGER)
+ *
+ * @deprecated
+ * Superceded by `fc.integer({max})` - see {@link https://github.com/dubzzz/fast-check/issues/992 | #992}.
+ * Ease the migration with {@link https://github.com/dubzzz/fast-check/tree/main/codemods/unify-signatures | our codemod script}.
+ *
+ * @remarks Since 0.0.1
+ * @public
+ */
+function integer(max: number): _IntegerMock<number>;
+/**
+ * For integers between min (included) and max (included)
+ *
+ * @param min - Lower bound for the generated integers (eg.: 0, Number.MIN_SAFE_INTEGER)
+ * @param max - Upper bound for the generated integers (eg.: 2147483647, Number.MAX_SAFE_INTEGER)
+ *
+ * @remarks You may prefer to use `fc.integer({min, max})` instead.
+ * @remarks Since 0.0.1
+ * @public
+ */
+function integer(min: number, max: number): _IntegerMock<number>;
+/**
+ * For integers between min (included) and max (included)
+ *
+ * @param constraints - Constraints to apply when building instances
+ *
+ * @remarks Since 2.6.0
+ * @public
+ */
+function integer(constraints: IntegerConstraints): _IntegerMock<number>;
+function integer(...args: [] | [number] | [number, number] | [IntegerConstraints]): _IntegerMock<number> {
+  const constraints = buildCompleteIntegerConstraints(extractIntegerConstraints(args));
+  if (constraints.min > constraints.max) {
+    throw new Error('fc.integer maximum value should be equal or greater than the minimum one');
+  }
+  const arb = new IntegerArbitrary(constraints.min, constraints.max);
+  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
+}
+export { integer };
diff --git a/src/arbitrary/maxSafeInteger.ts b/src/arbitrary/maxSafeInteger.ts
new file mode 100644
index 00000000..93a91393
--- /dev/null
+++ b/src/arbitrary/maxSafeInteger.ts
@@ -0,0 +1,13 @@
+import { ArbitraryWithContextualShrink } from '../check/arbitrary/definition/ArbitraryWithContextualShrink';
+import { convertFromNextWithShrunkOnce } from '../check/arbitrary/definition/Converters';
+import { IntegerArbitrary } from './_internals/IntegerArbitrary';
+
+/**
+ * For integers between Number.MIN_SAFE_INTEGER (included) and Number.MAX_SAFE_INTEGER (included)
+ * @remarks Since 1.11.0
+ * @public
+ */
+export function maxSafeInteger(): ArbitraryWithContextualShrink<number> {
+  const arb = new IntegerArbitrary(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
+  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
+}
diff --git a/src/arbitrary/maxSafeNat.ts b/src/arbitrary/maxSafeNat.ts
new file mode 100644
index 00000000..8be57720
--- /dev/null
+++ b/src/arbitrary/maxSafeNat.ts
@@ -0,0 +1,13 @@
+import { ArbitraryWithContextualShrink } from '../check/arbitrary/definition/ArbitraryWithContextualShrink';
+import { convertFromNextWithShrunkOnce } from '../check/arbitrary/definition/Converters';
+import { IntegerArbitrary } from './_internals/IntegerArbitrary';
+
+/**
+ * For positive integers between 0 (included) and Number.MAX_SAFE_INTEGER (included)
+ * @remarks Since 1.11.0
+ * @public
+ */
+export function maxSafeNat(): ArbitraryWithContextualShrink<number> {
+  const arb = new IntegerArbitrary(0, Number.MAX_SAFE_INTEGER);
+  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
+}
diff --git a/src/arbitrary/nat.ts b/src/arbitrary/nat.ts
new file mode 100644
index 00000000..098607f0
--- /dev/null
+++ b/src/arbitrary/nat.ts
@@ -0,0 +1,52 @@
+import { ArbitraryWithContextualShrink } from '../check/arbitrary/definition/ArbitraryWithContextualShrink';
+import { convertFromNextWithShrunkOnce } from '../check/arbitrary/definition/Converters';
+import { IntegerArbitrary } from './_internals/IntegerArbitrary';
+
+/**
+ * Constraints to be applied on {@link nat}
+ * @remarks Since 2.6.0
+ * @public
+ */
+export interface NatConstraints {
+  /**
+   * Upper bound for the generated postive integers (included)
+   * @defaultValue 0x7fffffff
+   * @remarks Since 2.6.0
+   */
+  max?: number;
+}
+
+/**
+ * For positive integers between 0 (included) and 2147483647 (included)
+ * @remarks Since 0.0.1
+ * @public
+ */
+function nat(): ArbitraryWithContextualShrink<number>;
+/**
+ * For positive integers between 0 (included) and max (included)
+ *
+ * @param max - Upper bound for the generated integers
+ *
+ * @remarks You may prefer to use `fc.nat({max})` instead.
+ * @remarks Since 0.0.1
+ * @public
+ */
+function nat(max: number): ArbitraryWithContextualShrink<number>;
+/**
+ * For positive integers between 0 (included) and max (included)
+ *
+ * @param constraints - Constraints to apply when building instances
+ *
+ * @remarks Since 2.6.0
+ * @public
+ */
+function nat(constraints: NatConstraints): ArbitraryWithContextualShrink<number>;
+function nat(arg?: number | NatConstraints): ArbitraryWithContextualShrink<number> {
+  const max = typeof arg === 'number' ? arg : arg && arg.max !== undefined ? arg.max : IntegerArbitrary.MAX_INT;
+  if (max < 0) {
+    throw new Error('fc.nat value should be greater than or equal to 0');
+  }
+  const arb = new IntegerArbitrary(0, max);
+  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
+}
+export { nat };
diff --git a/src/check/arbitrary/ArrayArbitrary.ts b/src/check/arbitrary/ArrayArbitrary.ts
index bbfc966e..0378e485 100644
--- a/src/check/arbitrary/ArrayArbitrary.ts
+++ b/src/check/arbitrary/ArrayArbitrary.ts
@@ -2,7 +2,7 @@ import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
 import { cloneIfNeeded, cloneMethod } from '../symbols';
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 import { makeLazy } from '../../stream/LazyIterableIterator';
 import { buildCompareFilter } from './helpers/BuildCompareFilter';
 import { NextArbitrary } from './definition/NextArbitrary';
diff --git a/src/check/arbitrary/BigIntArbitrary.ts b/src/check/arbitrary/BigIntArbitrary.ts
index 46fdff35..9e552116 100644
--- a/src/check/arbitrary/BigIntArbitrary.ts
+++ b/src/check/arbitrary/BigIntArbitrary.ts
@@ -4,7 +4,7 @@ import { ArbitraryWithContextualShrink } from './definition/ArbitraryWithContext
 import { convertFromNextWithShrunkOnce } from './definition/Converters';
 import { NextArbitrary } from './definition/NextArbitrary';
 import { NextValue } from './definition/NextValue';
-import { retrieveBiasRangesForNumeric, bigIntLogLike } from './helpers/BiasNumeric';
+import { biasNumericRange, bigIntLogLike } from '../../arbitrary/_internals/helpers/BiasNumericRange';
 import { shrinkBigInt } from './helpers/ShrinkBigInt';
 
 /** @internal */
@@ -21,7 +21,7 @@ class BigIntArbitrary extends NextArbitrary<bigint> {
     if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) {
       return { min: this.min, max: this.max };
     }
-    const ranges = retrieveBiasRangesForNumeric(this.min, this.max, bigIntLogLike);
+    const ranges = biasNumericRange(this.min, this.max, bigIntLogLike);
     if (ranges.length === 1) {
       return ranges[0];
     }
diff --git a/src/check/arbitrary/BooleanArbitrary.ts b/src/check/arbitrary/BooleanArbitrary.ts
index 814b6f6d..6d394521 100644
--- a/src/check/arbitrary/BooleanArbitrary.ts
+++ b/src/check/arbitrary/BooleanArbitrary.ts
@@ -1,5 +1,5 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 
 /**
  * For boolean values - `true` or `false`
diff --git a/src/check/arbitrary/CharacterArbitrary.ts b/src/check/arbitrary/CharacterArbitrary.ts
index ab74966d..1e8fee1e 100644
--- a/src/check/arbitrary/CharacterArbitrary.ts
+++ b/src/check/arbitrary/CharacterArbitrary.ts
@@ -1,5 +1,5 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 
 /** @internal */
 function CharacterArbitrary(min: number, max: number, mapToCode: (v: number) => number) {
diff --git a/src/check/arbitrary/DateArbitrary.ts b/src/check/arbitrary/DateArbitrary.ts
index f00c4164..f96a3cad 100644
--- a/src/check/arbitrary/DateArbitrary.ts
+++ b/src/check/arbitrary/DateArbitrary.ts
@@ -1,5 +1,5 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 
 /**
  * For date between constraints.min or new Date(-8640000000000000) (included) and constraints.max or new Date(8640000000000000) (included)
diff --git a/src/check/arbitrary/FloatNextArbitrary.ts b/src/check/arbitrary/FloatNextArbitrary.ts
index 879d3af7..38522964 100644
--- a/src/check/arbitrary/FloatNextArbitrary.ts
+++ b/src/check/arbitrary/FloatNextArbitrary.ts
@@ -1,5 +1,5 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 
 /** @internal */
 export const MIN_VALUE_32 = 2 ** -126 * 2 ** -23;
diff --git a/src/check/arbitrary/FloatingPointArbitrary.ts b/src/check/arbitrary/FloatingPointArbitrary.ts
index d1311af4..58283e8e 100644
--- a/src/check/arbitrary/FloatingPointArbitrary.ts
+++ b/src/check/arbitrary/FloatingPointArbitrary.ts
@@ -1,7 +1,7 @@
 import { Arbitrary } from './definition/Arbitrary';
 import { doubleNext, DoubleNextConstraints } from './DoubleNextArbitrary';
 import { floatNext, FloatNextConstraints } from './FloatNextArbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 import { tuple } from './TupleArbitrary';
 
 /** @internal */
diff --git a/src/check/arbitrary/FunctionArbitrary.ts b/src/check/arbitrary/FunctionArbitrary.ts
index f20a12b8..daec9071 100644
--- a/src/check/arbitrary/FunctionArbitrary.ts
+++ b/src/check/arbitrary/FunctionArbitrary.ts
@@ -3,7 +3,7 @@ import { stringify } from '../../utils/stringify';
 import { cloneMethod, hasCloneMethod } from '../symbols';
 import { array } from './ArrayArbitrary';
 import { Arbitrary } from './definition/Arbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 import { tuple } from './TupleArbitrary';
 import { escapeForMultilineComments } from './helpers/TextEscaper';
 
diff --git a/src/check/arbitrary/IntegerArbitrary.ts b/src/check/arbitrary/IntegerArbitrary.ts
deleted file mode 100644
index 95e02128..00000000
--- a/src/check/arbitrary/IntegerArbitrary.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-import { Random } from '../../random/generator/Random';
-import { Stream } from '../../stream/Stream';
-import { ArbitraryWithContextualShrink } from './definition/ArbitraryWithContextualShrink';
-import { convertFromNextWithShrunkOnce } from './definition/Converters';
-import { NextArbitrary } from './definition/NextArbitrary';
-import { NextValue } from './definition/NextValue';
-import { retrieveBiasRangesForNumeric, integerLogLike } from './helpers/BiasNumeric';
-import { shrinkInteger } from './helpers/ShrinkInteger';
-
-/** @internal */
-class IntegerArbitrary extends NextArbitrary<number> {
-  static MIN_INT: number = 0x80000000 | 0;
-  static MAX_INT: number = 0x7fffffff | 0;
-
-  constructor(readonly min: number, readonly max: number) {
-    super();
-  }
-
-  generate(mrng: Random, biasFactor: number | undefined): NextValue<number> {
-    const range = this.computeGenerateRange(mrng, biasFactor);
-    return new NextValue(mrng.nextInt(range.min, range.max), undefined);
-  }
-  private computeGenerateRange(mrng: Random, biasFactor: number | undefined): { min: number; max: number } {
-    if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) {
-      return { min: this.min, max: this.max };
-    }
-    const ranges = retrieveBiasRangesForNumeric(this.min, this.max, integerLogLike);
-    if (ranges.length === 1) {
-      return ranges[0];
-    }
-    const id = mrng.nextInt(-2 * (ranges.length - 1), ranges.length - 2); // 1st range has the highest priority
-    return id < 0 ? ranges[0] : ranges[id + 1];
-  }
-
-  canGenerate(value: unknown): value is number {
-    return typeof value === 'number' && Number.isInteger(value) && this.min <= value && value <= this.max;
-  }
-
-  shrink(current: number, context?: unknown): Stream<NextValue<number>> {
-    if (current === 0) {
-      return Stream.nil();
-    }
-    if (!IntegerArbitrary.isValidContext(current, context)) {
-      // No context:
-      //   Take default target and shrink towards it
-      //   Try the target on first try
-      const target = this.defaultTarget();
-      return shrinkInteger(current, target, true);
-    }
-    if (this.isLastChanceTry(current, context)) {
-      // Last chance try...
-      // context is set to undefined, so that shrink will restart
-      // without any assumptions in case our try find yet another bug
-      return Stream.of(new NextValue(context, undefined));
-    }
-    // Normal shrink process
-    return shrinkInteger(current, context, false);
-  }
-
-  defaultTarget(): number {
-    // min <= 0 && max >= 0   => shrink towards zero
-    if (this.min <= 0 && this.max >= 0) {
-      return 0;
-    }
-    // min < 0                => shrink towards max (closer to zero)
-    // otherwise              => shrink towards min (closer to zero)
-    return this.min < 0 ? this.max : this.min;
-  }
-
-  private isLastChanceTry(current: number, context: number): boolean {
-    // If true...
-    // We already reached what we thought to be the minimal failing value.
-    // But in-between other values may have shrunk (values coming from other arbitraries).
-    // In order to check if they impacted us, we just try to move very close to our current value.
-    // It is not ideal but it can help restart a shrinking process that stopped too early.
-    if (current > 0) return current === context + 1 && current > this.min;
-    if (current < 0) return current === context - 1 && current < this.max;
-    return false;
-  }
-
-  private static isValidContext(current: number, context?: unknown): context is number {
-    // Context contains a value between zero and current that is known to be
-    // the closer to zero passing value*.
-    // *More precisely: our shrinker will not try something closer to zero
-    if (context === undefined) {
-      return false;
-    }
-    if (typeof context !== 'number') {
-      throw new Error(`Invalid context type passed to IntegerArbitrary (#1)`);
-    }
-    if (context !== 0 && Math.sign(current) !== Math.sign(context)) {
-      throw new Error(`Invalid context value passed to IntegerArbitrary (#2)`);
-    }
-    return true;
-  }
-}
-
-/**
- * Constraints to be applied on {@link integer}
- * @remarks Since 2.6.0
- * @public
- */
-export interface IntegerConstraints {
-  /**
-   * Lower bound for the generated integers (included)
-   * @defaultValue -0x80000000
-   * @remarks Since 2.6.0
-   */
-  min?: number;
-  /**
-   * Upper bound for the generated integers (included)
-   * @defaultValue 0x7fffffff
-   * @remarks Since 2.6.0
-   */
-  max?: number;
-}
-
-/**
- * Build fully set IntegerConstraints from a partial data
- * @internal
- */
-function buildCompleteIntegerConstraints(constraints: IntegerConstraints): Required<IntegerConstraints> {
-  const min = constraints.min !== undefined ? constraints.min : IntegerArbitrary.MIN_INT;
-  const max = constraints.max !== undefined ? constraints.max : IntegerArbitrary.MAX_INT;
-  return { min, max };
-}
-
-/**
- * Extract constraints from args received by integer
- * @internal
- */
-function extractIntegerConstraints(args: [] | [number] | [number, number] | [IntegerConstraints]): IntegerConstraints {
-  if (args[0] === undefined) {
-    // integer()
-    return {};
-  } // args.length > 0
-
-  if (args[1] === undefined) {
-    const sargs = args as typeof args & [unknown]; // exactly 1 arg specified
-    if (typeof sargs[0] === 'number') return { max: sargs[0] }; // integer(max)
-    return sargs[0]; // integer(constraints)
-  } // args.length > 1
-
-  const sargs = args as typeof args & [unknown, unknown];
-  return { min: sargs[0], max: sargs[1] }; // integer(min, max)
-}
-
-/**
- * For integers between -2147483648 (included) and 2147483647 (included)
- * @remarks Since 0.0.1
- * @public
- */
-function integer(): ArbitraryWithContextualShrink<number>;
-/**
- * For integers between -2147483648 (included) and max (included)
- *
- * @param max - Upper bound for the generated integers (eg.: 2147483647, Number.MAX_SAFE_INTEGER)
- *
- * @deprecated
- * Superceded by `fc.integer({max})` - see {@link https://github.com/dubzzz/fast-check/issues/992 | #992}.
- * Ease the migration with {@link https://github.com/dubzzz/fast-check/tree/main/codemods/unify-signatures | our codemod script}.
- *
- * @remarks Since 0.0.1
- * @public
- */
-function integer(max: number): ArbitraryWithContextualShrink<number>;
-/**
- * For integers between min (included) and max (included)
- *
- * @param min - Lower bound for the generated integers (eg.: 0, Number.MIN_SAFE_INTEGER)
- * @param max - Upper bound for the generated integers (eg.: 2147483647, Number.MAX_SAFE_INTEGER)
- *
- * @remarks You may prefer to use `fc.integer({min, max})` instead.
- * @remarks Since 0.0.1
- * @public
- */
-function integer(min: number, max: number): ArbitraryWithContextualShrink<number>;
-/**
- * For integers between min (included) and max (included)
- *
- * @param constraints - Constraints to apply when building instances
- *
- * @remarks Since 2.6.0
- * @public
- */
-function integer(constraints: IntegerConstraints): ArbitraryWithContextualShrink<number>;
-function integer(
-  ...args: [] | [number] | [number, number] | [IntegerConstraints]
-): ArbitraryWithContextualShrink<number> {
-  const constraints = buildCompleteIntegerConstraints(extractIntegerConstraints(args));
-  if (constraints.min > constraints.max) {
-    throw new Error('fc.integer maximum value should be equal or greater than the minimum one');
-  }
-  const arb = new IntegerArbitrary(constraints.min, constraints.max);
-  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
-}
-
-/**
- * For integers between Number.MIN_SAFE_INTEGER (included) and Number.MAX_SAFE_INTEGER (included)
- * @remarks Since 1.11.0
- * @public
- */
-function maxSafeInteger(): ArbitraryWithContextualShrink<number> {
-  return integer(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
-}
-
-/**
- * Constraints to be applied on {@link nat}
- * @remarks Since 2.6.0
- * @public
- */
-export interface NatConstraints {
-  /**
-   * Upper bound for the generated postive integers (included)
-   * @defaultValue 0x7fffffff
-   * @remarks Since 2.6.0
-   */
-  max?: number;
-}
-
-/**
- * For positive integers between 0 (included) and 2147483647 (included)
- * @remarks Since 0.0.1
- * @public
- */
-function nat(): ArbitraryWithContextualShrink<number>;
-/**
- * For positive integers between 0 (included) and max (included)
- *
- * @param max - Upper bound for the generated integers
- *
- * @remarks You may prefer to use `fc.nat({max})` instead.
- * @remarks Since 0.0.1
- * @public
- */
-function nat(max: number): ArbitraryWithContextualShrink<number>;
-/**
- * For positive integers between 0 (included) and max (included)
- *
- * @param constraints - Constraints to apply when building instances
- *
- * @remarks Since 2.6.0
- * @public
- */
-function nat(constraints: NatConstraints): ArbitraryWithContextualShrink<number>;
-function nat(arg?: number | NatConstraints): ArbitraryWithContextualShrink<number> {
-  const max = typeof arg === 'number' ? arg : arg && arg.max !== undefined ? arg.max : IntegerArbitrary.MAX_INT;
-  if (max < 0) {
-    throw new Error('fc.nat value should be greater than or equal to 0');
-  }
-  const arb = new IntegerArbitrary(0, max);
-  return convertFromNextWithShrunkOnce(arb, arb.defaultTarget());
-}
-
-/**
- * For positive integers between 0 (included) and Number.MAX_SAFE_INTEGER (included)
- * @remarks Since 1.11.0
- * @public
- */
-function maxSafeNat(): ArbitraryWithContextualShrink<number> {
-  return nat(Number.MAX_SAFE_INTEGER);
-}
-
-export { integer, nat, maxSafeInteger, maxSafeNat };
diff --git a/src/check/arbitrary/IpArbitrary.ts b/src/check/arbitrary/IpArbitrary.ts
index 9a7f8217..150e05b4 100644
--- a/src/check/arbitrary/IpArbitrary.ts
+++ b/src/check/arbitrary/IpArbitrary.ts
@@ -1,7 +1,7 @@
 import { array } from './ArrayArbitrary';
 import { constantFrom } from './ConstantArbitrary';
 import { Arbitrary } from './definition/Arbitrary';
-import { nat } from './IntegerArbitrary';
+import { nat } from '../../arbitrary/nat';
 import { oneof } from './OneOfArbitrary';
 import { hexaString } from './StringArbitrary';
 import { tuple } from './TupleArbitrary';
diff --git a/src/check/arbitrary/MapToConstantArbitrary.ts b/src/check/arbitrary/MapToConstantArbitrary.ts
index ab24d3cf..d4ecbb00 100644
--- a/src/check/arbitrary/MapToConstantArbitrary.ts
+++ b/src/check/arbitrary/MapToConstantArbitrary.ts
@@ -1,5 +1,5 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { nat } from './IntegerArbitrary';
+import { nat } from '../../arbitrary/nat';
 
 /** @internal */
 function computeNumChoices<T>(options: { num: number; build: (idInGroup: number) => T }[]): number {
diff --git a/src/check/arbitrary/ObjectArbitrary.ts b/src/check/arbitrary/ObjectArbitrary.ts
index 231c89f1..4c6aeb25 100644
--- a/src/check/arbitrary/ObjectArbitrary.ts
+++ b/src/check/arbitrary/ObjectArbitrary.ts
@@ -7,7 +7,7 @@ import { constant } from './ConstantArbitrary';
 import { dictionary, toObject } from './DictionaryArbitrary';
 import { double } from './FloatingPointArbitrary';
 import { frequency } from './FrequencyArbitrary';
-import { maxSafeInteger } from './IntegerArbitrary';
+import { maxSafeInteger } from '../../arbitrary/maxSafeInteger';
 import { memo, Memo } from './MemoArbitrary';
 import { oneof } from './OneOfArbitrary';
 import { set } from './SetArbitrary';
diff --git a/src/check/arbitrary/SparseArrayArbitrary.ts b/src/check/arbitrary/SparseArrayArbitrary.ts
index 5f10b166..92295249 100644
--- a/src/check/arbitrary/SparseArrayArbitrary.ts
+++ b/src/check/arbitrary/SparseArrayArbitrary.ts
@@ -1,6 +1,6 @@
 import { maxLengthFromMinLength } from './ArrayArbitrary';
 import { Arbitrary } from './definition/Arbitrary';
-import { nat } from './IntegerArbitrary';
+import { nat } from '../../arbitrary/nat';
 import { set } from './SetArbitrary';
 import { tuple } from './TupleArbitrary';
 
diff --git a/src/check/arbitrary/SubarrayArbitrary.ts b/src/check/arbitrary/SubarrayArbitrary.ts
index 00e08a69..a0a6560e 100644
--- a/src/check/arbitrary/SubarrayArbitrary.ts
+++ b/src/check/arbitrary/SubarrayArbitrary.ts
@@ -4,7 +4,7 @@ import { Arbitrary } from './definition/Arbitrary';
 import { ArbitraryWithContextualShrink } from './definition/ArbitraryWithContextualShrink';
 import { biasWrapper } from './definition/BiasedArbitraryWrapper';
 import { Shrinkable } from './definition/Shrinkable';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 import { makeLazy } from '../../stream/LazyIterableIterator';
 
 /** @internal */
diff --git a/src/check/arbitrary/TypedArrayArbitrary.ts b/src/check/arbitrary/TypedArrayArbitrary.ts
index 46156c05..765a67ab 100644
--- a/src/check/arbitrary/TypedArrayArbitrary.ts
+++ b/src/check/arbitrary/TypedArrayArbitrary.ts
@@ -3,7 +3,7 @@ import { Arbitrary } from './definition/Arbitrary';
 import { DoubleNextConstraints } from './DoubleNextArbitrary';
 import { double, float } from './FloatingPointArbitrary';
 import { FloatNextConstraints } from './FloatNextArbitrary';
-import { integer } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
 
 /** @internal */
 type TypedIntArrayBuilderConstraints<TValue> = {
diff --git a/src/check/arbitrary/UuidArbitrary.ts b/src/check/arbitrary/UuidArbitrary.ts
index 03d83ac3..81fe65f8 100644
--- a/src/check/arbitrary/UuidArbitrary.ts
+++ b/src/check/arbitrary/UuidArbitrary.ts
@@ -1,5 +1,6 @@
 import { Arbitrary } from './definition/Arbitrary';
-import { integer, nat } from './IntegerArbitrary';
+import { integer } from '../../arbitrary/integer';
+import { nat } from '../../arbitrary/nat';
 import { tuple } from './TupleArbitrary';
 
 /** @internal */
diff --git a/src/check/arbitrary/WebArbitrary.ts b/src/check/arbitrary/WebArbitrary.ts
index 880af55f..c0c82547 100644
--- a/src/check/arbitrary/WebArbitrary.ts
+++ b/src/check/arbitrary/WebArbitrary.ts
@@ -3,7 +3,7 @@ import { constantFrom } from './ConstantArbitrary';
 import { constant } from './ConstantArbitrary';
 import { buildAlphaNumericPercentArb } from './helpers/SpecificCharacterRange';
 import { domain, hostUserInfo } from './HostArbitrary';
-import { nat } from './IntegerArbitrary';
+import { nat } from '../../arbitrary/nat';
 import { ipV4, ipV4Extended, ipV6 } from './IpArbitrary';
 import { oneof } from './OneOfArbitrary';
 import { option } from './OptionArbitrary';
diff --git a/src/check/model/commands/CommandsArbitrary.ts b/src/check/model/commands/CommandsArbitrary.ts
index e8e9c5b2..b7405002 100644
--- a/src/check/model/commands/CommandsArbitrary.ts
+++ b/src/check/model/commands/CommandsArbitrary.ts
@@ -3,7 +3,7 @@ import { Stream } from '../../../stream/Stream';
 import { Arbitrary } from '../../arbitrary/definition/Arbitrary';
 import { ArbitraryWithContextualShrink } from '../../arbitrary/definition/ArbitraryWithContextualShrink';
 import { Shrinkable } from '../../arbitrary/definition/Shrinkable';
-import { nat } from '../../arbitrary/IntegerArbitrary';
+import { nat } from '../../../arbitrary/nat';
 import { oneof } from '../../arbitrary/OneOfArbitrary';
 import { AsyncCommand } from '../command/AsyncCommand';
 import { Command } from '../command/Command';
diff --git a/src/fast-check-default.ts b/src/fast-check-default.ts
index 4efeffb1..8a707a2a 100644
--- a/src/fast-check-default.ts
+++ b/src/fast-check-default.ts
@@ -49,14 +49,10 @@ import {
 } from './check/arbitrary/FrequencyArbitrary';
 import { compareBooleanFunc, compareFunc, func } from './check/arbitrary/FunctionArbitrary';
 import { domain } from './check/arbitrary/HostArbitrary';
-import {
-  integer,
-  maxSafeInteger,
-  maxSafeNat,
-  nat,
-  IntegerConstraints,
-  NatConstraints,
-} from './check/arbitrary/IntegerArbitrary';
+import { integer, IntegerConstraints } from './arbitrary/integer';
+import { maxSafeInteger } from './arbitrary/maxSafeInteger';
+import { maxSafeNat } from './arbitrary/maxSafeNat';
+import { nat, NatConstraints } from './arbitrary/nat';
 import { ipV4, ipV4Extended, ipV6 } from './check/arbitrary/IpArbitrary';
 import { letrec } from './check/arbitrary/LetRecArbitrary';
 import { lorem, LoremConstraints } from './check/arbitrary/LoremArbitrary';


Test patch:
diff --git a/test/unit/check/arbitrary/IntegerArbitrary.spec.ts b/test/unit/arbitrary/IntegerArbitrary.spec.ts
similarity index 96%
rename from test/unit/check/arbitrary/IntegerArbitrary.spec.ts
rename to test/unit/arbitrary/IntegerArbitrary.spec.ts
index 1176f66d..ffb594e0 100644
--- a/test/unit/check/arbitrary/IntegerArbitrary.spec.ts
+++ b/test/unit/arbitrary/IntegerArbitrary.spec.ts
@@ -1,12 +1,15 @@
-import * as fc from '../../../../lib/fast-check';
+import * as fc from '../../../lib/fast-check';
 
-import { integer, nat, maxSafeNat, maxSafeInteger } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { integer } from '../../../src/arbitrary/integer';
+import { nat } from '../../../src/arbitrary/nat';
+import { maxSafeNat } from '../../../src/arbitrary/maxSafeNat';
+import { maxSafeInteger } from '../../../src/arbitrary/maxSafeInteger';
 
-import * as genericHelper from './generic/GenericArbitraryHelper';
+import * as genericHelper from '../check/arbitrary/generic/GenericArbitraryHelper';
 
-import * as stubRng from '../../stubs/generators';
-import { generateOneValue } from './generic/GenerateOneValue';
-import { buildShrinkTree, renderTree } from './generic/ShrinkTree';
+import * as stubRng from '../stubs/generators';
+import { generateOneValue } from '../check/arbitrary/generic/GenerateOneValue';
+import { buildShrinkTree, renderTree } from '../check/arbitrary/generic/ShrinkTree';
 
 const isStrictlySmallerInteger = (v1: number, v2: number) => Math.abs(v1) < Math.abs(v2);
 
diff --git a/test/unit/arbitrary/_internals/helpers/BiasNumericRange.spec.ts b/test/unit/arbitrary/_internals/helpers/BiasNumericRange.spec.ts
new file mode 100644
index 00000000..805df9df
--- /dev/null
+++ b/test/unit/arbitrary/_internals/helpers/BiasNumericRange.spec.ts
@@ -0,0 +1,129 @@
+import * as fc from '../../../../../lib/fast-check';
+import {
+  biasNumericRange,
+  bigIntLogLike,
+  integerLogLike,
+} from '../../../../../src/arbitrary/_internals/helpers/BiasNumericRange';
+
+describe('biasNumericRange', () => {
+  it('should bias close to extreme values and zero if min and max have opposite signs', () =>
+    fc.assert(
+      fc.property(fc.integer(Number.MIN_SAFE_INTEGER, -1), fc.integer(1, Number.MAX_SAFE_INTEGER), (min, max) => {
+        // Arrange / Act
+        const ranges = biasNumericRange(min, max, integerLogLike);
+
+        // Assert
+        expect(ranges).toHaveLength(3);
+        expect(ranges).toEqual([
+          { min: expect.toBeWithinRange(min, 0), max: expect.toBeWithinRange(0, max) }, // close to zero
+          { min: expect.toBeWithinRange(0, max), max: max }, // close to max
+          { min: min, max: expect.toBeWithinRange(min, 0) }, // close to min
+        ]);
+      })
+    ));
+
+  it('should bias close to extreme values if min and max have same signs', () =>
+    fc.assert(
+      fc.property(
+        fc.constantFrom(1, -1),
+        fc.integer(0, Number.MAX_SAFE_INTEGER),
+        fc.integer(0, Number.MAX_SAFE_INTEGER),
+        (sign, minRaw, maxRaw) => {
+          // Arrange
+          fc.pre(minRaw !== maxRaw);
+          const minRawSigned = sign * minRaw;
+          const maxRawSigned = sign * maxRaw;
+          const [min, max] = minRawSigned < maxRawSigned ? [minRawSigned, maxRawSigned] : [maxRawSigned, minRawSigned];
+
+          // Act
+          const ranges = biasNumericRange(min, max, integerLogLike);
+
+          // Assert
+          expect(ranges).toHaveLength(2);
+          const closeToMin = { min: expect.toBeWithinRange(min + 1, max), max: max }; // close to max
+          const closeToMax = { min: min, max: expect.toBeWithinRange(min, max - 1) }; // close to min
+          if (sign > 0) expect(ranges).toEqual([closeToMax, closeToMin]);
+          else expect(ranges).toEqual([closeToMin, closeToMax]);
+        }
+      )
+    ));
+
+  it('should not bias anything for equal values of min and max', () =>
+    fc.assert(
+      fc.property(fc.maxSafeInteger(), (minMax) => {
+        // Arrange / Act
+        const ranges = biasNumericRange(minMax, minMax, integerLogLike);
+
+        // Assert
+        expect(ranges).toHaveLength(1);
+        expect(ranges).toEqual([{ min: minMax, max: minMax }]); // no bias, cannot do more
+      })
+    ));
+
+  it('should always bias in valid ranges when using integerLogLike', () =>
+    fc.assert(
+      fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), (a, b) => {
+        // Arrange
+        const min = a < b ? a : b;
+        const max = a < b ? b : a;
+
+        // Act
+        const ranges = biasNumericRange(min, max, integerLogLike);
+
+        // Assert
+        expect(ranges).not.toHaveLength(0);
+        for (const range of ranges) {
+          expect(range.max).toBeGreaterThanOrEqual(range.min);
+          expect(min).toBeLessThanOrEqual(range.max);
+          expect(max).toBeGreaterThanOrEqual(range.max);
+          expect(min).toBeLessThanOrEqual(range.min);
+          expect(max).toBeGreaterThanOrEqual(range.min);
+        }
+      })
+    ));
+
+  if (typeof BigInt !== 'undefined') {
+    it('should always bias in valid ranges when using bigIntLogLike', () =>
+      fc.assert(
+        fc.property(fc.bigInt(), fc.bigInt(), (a, b) => {
+          // Arrange
+          const min = a < b ? a : b;
+          const max = a < b ? b : a;
+
+          // Act
+          const ranges = biasNumericRange(min, max, bigIntLogLike);
+
+          // Assert
+          expect(ranges).not.toHaveLength(0);
+          for (const range of ranges) {
+            expect(range.max).toBeGreaterThanOrEqual(range.min);
+            expect(min).toBeLessThanOrEqual(range.max);
+            expect(max).toBeGreaterThanOrEqual(range.max);
+            expect(min).toBeLessThanOrEqual(range.min);
+            expect(max).toBeGreaterThanOrEqual(range.min);
+          }
+        })
+      ));
+  }
+});
+
+// Helpers
+
+expect.extend({
+  toBeWithinRange(received, floor, ceiling): jest.CustomMatcherResult {
+    const pass = received >= floor && received <= ceiling && !Number.isNaN(received);
+    return {
+      message: () => `expected ${received} ${pass ? 'not ' : ''} to be within range ${floor} - ${ceiling}`,
+      pass,
+    };
+  },
+});
+
+declare global {
+  // eslint-disable-next-line @typescript-eslint/no-namespace
+  namespace jest {
+    interface Expect {
+      toBeWithinRange(a: number, b: number): CustomMatcherResult;
+    }
+  }
+}
diff --git a/test/unit/check/arbitrary/ArrayArbitrary.spec.ts b/test/unit/check/arbitrary/ArrayArbitrary.spec.ts
index 9a744572..a59b13a0 100644
--- a/test/unit/check/arbitrary/ArrayArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/ArrayArbitrary.spec.ts
@@ -4,7 +4,7 @@ import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary'
 import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
 import { array } from '../../../../src/check/arbitrary/ArrayArbitrary';
 import { context } from '../../../../src/check/arbitrary/ContextArbitrary';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 import { Random } from '../../../../src/random/generator/Random';
 
 import { isStrictlySmallerArray } from './generic/ArrayHelpers';
diff --git a/test/unit/check/arbitrary/CloneArbitrary.spec.ts b/test/unit/check/arbitrary/CloneArbitrary.spec.ts
index c2c65d46..7dce09a8 100644
--- a/test/unit/check/arbitrary/CloneArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/CloneArbitrary.spec.ts
@@ -1,7 +1,7 @@
 import * as fc from '../../../../lib/fast-check';
 
 import { clone } from '../../../../src/check/arbitrary/CloneArbitrary';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 
 import * as genericHelper from './generic/GenericArbitraryHelper';
 
diff --git a/test/unit/check/arbitrary/DateArbitrary.utest.spec.ts b/test/unit/check/arbitrary/DateArbitrary.utest.spec.ts
index 850035a8..be3f4577 100644
--- a/test/unit/check/arbitrary/DateArbitrary.utest.spec.ts
+++ b/test/unit/check/arbitrary/DateArbitrary.utest.spec.ts
@@ -4,13 +4,11 @@ import { mocked } from 'ts-jest/utils';
 import * as fc from '../../../../lib/fast-check';
 import { ArbitraryWithShrink } from '../../../../src/check/arbitrary/definition/ArbitraryWithShrink';
 
-jest.mock('../../../../src/check/arbitrary/IntegerArbitrary');
-import * as _IntegerArbitraryMock from '../../../../src/check/arbitrary/IntegerArbitrary';
+jest.mock('../../../../src/arbitrary/integer');
+import * as _IntegerMock from '../../../../src/arbitrary/integer';
 import { arbitraryFor } from './generic/ArbitraryBuilder';
 
-const IntegerArbitraryMock: {
-  integer: (min: number, max: number) => ArbitraryWithShrink<number>;
-} = _IntegerArbitraryMock;
+const IntegerArbitraryMock: { integer: (min: number, max: number) => ArbitraryWithShrink<number> } = _IntegerMock;
 
 const mrng = () => stubRng.mutable.nocall();
 
diff --git a/test/unit/check/arbitrary/FloatNextArbitrary.utest.spec.ts b/test/unit/check/arbitrary/FloatNextArbitrary.utest.spec.ts
index 2ccf1e82..87e30d8c 100644
--- a/test/unit/check/arbitrary/FloatNextArbitrary.utest.spec.ts
+++ b/test/unit/check/arbitrary/FloatNextArbitrary.utest.spec.ts
@@ -24,8 +24,8 @@ import { mocked } from 'ts-jest/utils';
 import { arbitraryFor } from './generic/ArbitraryBuilder';
 import * as stubRng from '../../stubs/generators';
 
-import * as IntegerArbitraryMock from '../../../../src/check/arbitrary/IntegerArbitrary';
-jest.mock('../../../../src/check/arbitrary/IntegerArbitrary');
+import * as IntegerMock from '../../../../src/arbitrary/integer';
+jest.mock('../../../../src/arbitrary/integer');
 
 const mrng = () => stubRng.mutable.nocall();
 
@@ -40,7 +40,7 @@ function minMaxForConstraints(ct: FloatNextConstraints) {
 
 function mockNoOpIntegerArb(opts: { single?: boolean } = {}) {
   // Mocking integer: not expecting any call there
-  const { integer } = mocked(IntegerArbitraryMock);
+  const { integer } = mocked(IntegerMock);
   if (opts.single) integer.mockImplementationOnce(() => arbitraryFor([]));
   else integer.mockImplementation(() => arbitraryFor([]));
   return integer;
@@ -117,7 +117,7 @@ describe('FloatNextArbitrary', () => {
       fc.assert(
         fc.property(fc.option(floatNextConstraints(), { nil: undefined }), fc.maxSafeNat(), (ct, mod) => {
           // Arrange
-          const { integer } = mocked(IntegerArbitraryMock);
+          const { integer } = mocked(IntegerMock);
           const { min, max } = minMaxForConstraints(ct || {});
           const minIndex = floatToIndex(min);
           const maxIndex = floatToIndex(max);
diff --git a/test/unit/check/arbitrary/FrequencyArbitrary.itest.spec.ts b/test/unit/check/arbitrary/FrequencyArbitrary.itest.spec.ts
index a8a91e09..b38b4a6d 100644
--- a/test/unit/check/arbitrary/FrequencyArbitrary.itest.spec.ts
+++ b/test/unit/check/arbitrary/FrequencyArbitrary.itest.spec.ts
@@ -1,7 +1,7 @@
 import * as fc from '../../../../lib/fast-check';
 
 import { frequency } from '../../../../src/check/arbitrary/FrequencyArbitrary';
-import { integer } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { integer } from '../../../../src/arbitrary/integer';
 import { constant } from '../../../../src/check/arbitrary/ConstantArbitrary';
 
 import * as genericHelper from './generic/GenericArbitraryHelper';
diff --git a/test/unit/check/arbitrary/FunctionArbitrary.spec.ts b/test/unit/check/arbitrary/FunctionArbitrary.spec.ts
index 2c53519b..cccbd951 100644
--- a/test/unit/check/arbitrary/FunctionArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/FunctionArbitrary.spec.ts
@@ -2,7 +2,7 @@ import * as fc from '../../../../lib/fast-check';
 
 import { func, compareFunc, compareBooleanFunc } from '../../../../src/check/arbitrary/FunctionArbitrary';
 import { context } from '../../../../src/check/arbitrary/ContextArbitrary';
-import { integer } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { integer } from '../../../../src/arbitrary/integer';
 import { hasCloneMethod, cloneMethod } from '../../../../src/check/symbols';
 import { hash } from '../../../../src/utils/hash';
 import { stringify } from '../../../../src/utils/stringify';
diff --git a/test/unit/check/arbitrary/MapToConstantArbitrary.spec.ts b/test/unit/check/arbitrary/MapToConstantArbitrary.spec.ts
index 6208f362..183f0573 100644
--- a/test/unit/check/arbitrary/MapToConstantArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/MapToConstantArbitrary.spec.ts
@@ -4,7 +4,7 @@ import * as fc from '../../../../lib/fast-check';
 import { mapToConstant } from '../../../../src/check/arbitrary/MapToConstantArbitrary';
 import { Random } from '../../../../src/random/generator/Random';
 import { minMax } from './generic/GenericArbitraryHelper';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 
 describe('MapToConstantArbitrary', () => {
   describe('mapToConstant', () => {
diff --git a/test/unit/check/arbitrary/MixedCaseArbitrary.itest.spec.ts b/test/unit/check/arbitrary/MixedCaseArbitrary.itest.spec.ts
index ef22b315..ce2a093c 100644
--- a/test/unit/check/arbitrary/MixedCaseArbitrary.itest.spec.ts
+++ b/test/unit/check/arbitrary/MixedCaseArbitrary.itest.spec.ts
@@ -1,4 +1,4 @@
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 import { stringOf } from '../../../../src/check/arbitrary/StringArbitrary';
 import { mixedCase } from '../../../../src/check/arbitrary/MixedCaseArbitrary';
 
diff --git a/test/unit/check/arbitrary/OneOfArbitrary.itest.spec.ts b/test/unit/check/arbitrary/OneOfArbitrary.itest.spec.ts
index df13e95a..9a133f82 100644
--- a/test/unit/check/arbitrary/OneOfArbitrary.itest.spec.ts
+++ b/test/unit/check/arbitrary/OneOfArbitrary.itest.spec.ts
@@ -3,7 +3,7 @@ import * as fc from '../../../../lib/fast-check';
 import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
 import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
 import { constant } from '../../../../src/check/arbitrary/ConstantArbitrary';
-import { integer } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { integer } from '../../../../src/arbitrary/integer';
 import { oneof } from '../../../../src/check/arbitrary/OneOfArbitrary';
 import { Random } from '../../../../src/random/generator/Random';
 import { stream } from '../../../../src/stream/Stream';
diff --git a/test/unit/check/arbitrary/RecordArbitrary.spec.ts b/test/unit/check/arbitrary/RecordArbitrary.spec.ts
index 3542d40a..3e20fdad 100644
--- a/test/unit/check/arbitrary/RecordArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/RecordArbitrary.spec.ts
@@ -3,7 +3,7 @@ import * as fc from '../../../../lib/fast-check';
 
 import { constant } from '../../../../src/check/arbitrary/ConstantArbitrary';
 import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
-import { integer } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { integer } from '../../../../src/arbitrary/integer';
 import { record, RecordConstraints } from '../../../../src/check/arbitrary/RecordArbitrary';
 import { Random } from '../../../../src/random/generator/Random';
 
diff --git a/test/unit/check/arbitrary/SetArbitrary.spec.ts b/test/unit/check/arbitrary/SetArbitrary.spec.ts
index 24203ec5..1ade3ea2 100644
--- a/test/unit/check/arbitrary/SetArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/SetArbitrary.spec.ts
@@ -1,7 +1,7 @@
 import * as fc from '../../../../lib/fast-check';
 
 import { set } from '../../../../src/check/arbitrary/SetArbitrary';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 import { string } from '../../../../src/check/arbitrary/StringArbitrary';
 
 import { generateOneValue } from './generic/GenerateOneValue';
diff --git a/test/unit/check/arbitrary/SparseArrayArbitrary.itest.spec.ts b/test/unit/check/arbitrary/SparseArrayArbitrary.itest.spec.ts
index 727f2adf..32712bac 100644
--- a/test/unit/check/arbitrary/SparseArrayArbitrary.itest.spec.ts
+++ b/test/unit/check/arbitrary/SparseArrayArbitrary.itest.spec.ts
@@ -1,5 +1,5 @@
 import { sparseArray, SparseArrayConstraints } from '../../../../src/check/arbitrary/SparseArrayArbitrary';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 import * as genericHelper from './generic/GenericArbitraryHelper';
 import fc from '../../../../lib/fast-check';
 
diff --git a/test/unit/check/arbitrary/SparseArrayArbitrary.utest.spec.ts b/test/unit/check/arbitrary/SparseArrayArbitrary.utest.spec.ts
index dfc479b2..b46145e4 100644
--- a/test/unit/check/arbitrary/SparseArrayArbitrary.utest.spec.ts
+++ b/test/unit/check/arbitrary/SparseArrayArbitrary.utest.spec.ts
@@ -5,11 +5,11 @@ import { mocked } from 'ts-jest/utils';
 
 import fc from '../../../../lib/fast-check';
 
-import * as IntegerArbitraryMock from '../../../../src/check/arbitrary/IntegerArbitrary';
+import * as NatMock from '../../../../src/arbitrary/nat';
 import * as SetArbitraryMock from '../../../../src/check/arbitrary/SetArbitrary';
 import * as TupleArbitraryMock from '../../../../src/check/arbitrary/TupleArbitrary';
 import { arbitraryFor } from './generic/ArbitraryBuilder';
-jest.mock('../../../../src/check/arbitrary/IntegerArbitrary');
+jest.mock('../../../../src/arbitrary/nat');
 jest.mock('../../../../src/check/arbitrary/SetArbitrary');
 jest.mock('../../../../src/check/arbitrary/TupleArbitrary');
 
@@ -92,7 +92,7 @@ describe('SparseArrayArbitrary', () => {
             fc.pre(!isLimitNoTrailingCase(ct));
             const { set } = mocked(SetArbitraryMock);
             const { tuple } = mocked(TupleArbitraryMock);
-            const { nat } = mocked(IntegerArbitraryMock); // called to build indexes
+            const { nat } = mocked(NatMock); // called to build indexes
             set.mockImplementationOnce(() => arbitraryFor([{ value: [] }]));
             tuple.mockImplementationOnce(() => arbitraryFor([{ value: [] as any }]));
 
diff --git a/test/unit/check/arbitrary/StreamArbitrary.spec.ts b/test/unit/check/arbitrary/StreamArbitrary.spec.ts
index f73c4cf0..7929d123 100644
--- a/test/unit/check/arbitrary/StreamArbitrary.spec.ts
+++ b/test/unit/check/arbitrary/StreamArbitrary.spec.ts
@@ -1,7 +1,7 @@
 import * as fc from '../../../../lib/fast-check';
 
 import { context } from '../../../../src/check/arbitrary/ContextArbitrary';
-import { nat } from '../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../src/arbitrary/nat';
 import { infiniteStream } from '../../../../src/check/arbitrary/StreamArbitrary';
 import { Stream } from '../../../../src/stream/Stream';
 
diff --git a/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts b/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts
index e12afcbe..e6651fd9 100644
--- a/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts
+++ b/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts
@@ -13,9 +13,9 @@ import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary'
 
 import { mocked } from 'ts-jest/utils';
 jest.mock('../../../../src/check/arbitrary/ArrayArbitrary');
-jest.mock('../../../../src/check/arbitrary/IntegerArbitrary');
+jest.mock('../../../../src/arbitrary/integer');
 import * as ArrayArbitraryMock from '../../../../src/check/arbitrary/ArrayArbitrary';
-import * as IntegerArbitraryMock from '../../../../src/check/arbitrary/IntegerArbitrary';
+import * as IntegerMock from '../../../../src/arbitrary/integer';
 
 const validArrayConstraintsArb = () =>
   fc.record({ minLength: fc.nat(), maxLength: fc.nat() }, { withDeletedKeys: true }).map((ct) => {
@@ -87,7 +87,7 @@ function assessValidIntTypedArray<T>(
 
   it('Should default constraints when not specified', () => {
     // Arrange
-    const { integer } = mocked(IntegerArbitraryMock);
+    const { integer } = mocked(IntegerMock);
     const { array } = mocked(ArrayArbitraryMock);
     const integerArb = Symbol() as any;
     integer.mockReturnValue(integerArb);
@@ -106,7 +106,7 @@ function assessValidIntTypedArray<T>(
     fc.assert(
       fc.property(validArrayConstraintsArb(), validIntegerConstraintsArb(lowestInt, highestInt), (ctArray, ctInt) => {
         // Arrange
-        const { integer } = mocked(IntegerArbitraryMock);
+        const { integer } = mocked(IntegerMock);
         const { array } = mocked(ArrayArbitraryMock);
         const integerArb = Symbol() as any;
         integer.mockReturnValue(integerArb);
@@ -126,7 +126,7 @@ function assessValidIntTypedArray<T>(
     fc.assert(
       fc.property(validArrayConstraintsArb(), invalidIntegerConstraintsArb(lowestInt, highestInt), (ctArray, ctInt) => {
         // Arrange
-        const { integer } = mocked(IntegerArbitraryMock);
+        const { integer } = mocked(IntegerMock);
         const { array } = mocked(ArrayArbitraryMock);
         const integerArb = Symbol() as any;
         integer.mockReturnValue(integerArb);
diff --git a/test/unit/check/arbitrary/UuidArbitrary.utest.spec.ts b/test/unit/check/arbitrary/UuidArbitrary.utest.spec.ts
index 98646360..a468797e 100644
--- a/test/unit/check/arbitrary/UuidArbitrary.utest.spec.ts
+++ b/test/unit/check/arbitrary/UuidArbitrary.utest.spec.ts
@@ -3,16 +3,16 @@ import * as stubRng from '../../stubs/generators';
 import { mocked } from 'ts-jest/utils';
 import { ArbitraryWithShrink } from '../../../../src/check/arbitrary/definition/ArbitraryWithShrink';
 
-jest.mock('../../../../src/check/arbitrary/IntegerArbitrary');
+jest.mock('../../../../src/arbitrary/integer');
+jest.mock('../../../../src/arbitrary/nat');
 jest.mock('../../../../src/check/arbitrary/TupleArbitrary');
-import * as _IntegerArbitraryMock from '../../../../src/check/arbitrary/IntegerArbitrary';
+import * as _IntegerMock from '../../../../src/arbitrary/integer';
+import * as _NatMock from '../../../../src/arbitrary/nat';
 import * as TupleArbitraryMock from '../../../../src/check/arbitrary/TupleArbitrary';
 import { arbitraryFor } from './generic/ArbitraryBuilder';
 
-const IntegerArbitraryMock: {
-  integer: (min: number, max: number) => ArbitraryWithShrink<number>;
-  nat: (max: number) => ArbitraryWithShrink<number>;
-} = _IntegerArbitraryMock;
+const IntegerMock: { integer: (min: number, max: number) => ArbitraryWithShrink<number> } = _IntegerMock;
+const NatMock: { nat: (max: number) => ArbitraryWithShrink<number> } = _NatMock;
 
 const mrng = () => stubRng.mutable.nocall();
 
@@ -23,7 +23,8 @@ describe('UuidArbitrary', () => {
     });
     it('Should be able to build the smallest uuid', () => {
       // Arrange
-      const { nat, integer } = mocked(IntegerArbitraryMock);
+      const { integer } = mocked(IntegerMock);
+      const { nat } = mocked(NatMock);
       const { tuple } = mocked(TupleArbitraryMock);
       nat.mockImplementation(() => arbitraryFor([{ value: 0 }, { value: 0 }, { value: 0 }]));
       integer.mockImplementation((a, _b) => arbitraryFor([{ value: a }]));
@@ -41,7 +42,8 @@ describe('UuidArbitrary', () => {
     });
     it('Should be able to build the largest uuid', () => {
       // Arrange
-      const { nat, integer } = mocked(IntegerArbitraryMock);
+      const { integer } = mocked(IntegerMock);
+      const { nat } = mocked(NatMock);
       const { tuple } = mocked(TupleArbitraryMock);
       nat.mockImplementation((a) => arbitraryFor([{ value: a }, { value: a }, { value: a }]));
       integer.mockImplementation((a, b) => arbitraryFor([{ value: b }]));
@@ -64,7 +66,8 @@ describe('UuidArbitrary', () => {
     });
     it('Should be able to build the smallest versioned uuid', () => {
       // Arrange
-      const { nat, integer } = mocked(IntegerArbitraryMock);
+      const { integer } = mocked(IntegerMock);
+      const { nat } = mocked(NatMock);
       const { tuple } = mocked(TupleArbitraryMock);
       nat.mockImplementation(() => arbitraryFor([{ value: 0 }, { value: 0 }]));
       integer.mockImplementation((a, _b) => arbitraryFor([{ value: a }]));
@@ -82,7 +85,8 @@ describe('UuidArbitrary', () => {
     });
     it('Should be able to build the largest versioned uuid', () => {
       // Arrange
-      const { nat, integer } = mocked(IntegerArbitraryMock);
+      const { integer } = mocked(IntegerMock);
+      const { nat } = mocked(NatMock);
       const { tuple } = mocked(TupleArbitraryMock);
       nat.mockImplementation((a) => arbitraryFor([{ value: a }, { value: a }]));
       integer.mockImplementation((a, b) => arbitraryFor([{ value: b }]));
diff --git a/test/unit/check/arbitrary/definition/Arbitrary.itest.spec.ts b/test/unit/check/arbitrary/definition/Arbitrary.itest.spec.ts
index ef8d5704..ca3f845d 100644
--- a/test/unit/check/arbitrary/definition/Arbitrary.itest.spec.ts
+++ b/test/unit/check/arbitrary/definition/Arbitrary.itest.spec.ts
@@ -3,7 +3,7 @@ import * as fc from '../../../../../lib/fast-check';
 import { constant } from '../../../../../src/check/arbitrary/ConstantArbitrary';
 import { Arbitrary } from '../../../../../src/check/arbitrary/definition/Arbitrary';
 import { Shrinkable } from '../../../../../src/check/arbitrary/definition/Shrinkable';
-import { nat } from '../../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../../src/arbitrary/nat';
 import { tuple } from '../../../../../src/check/arbitrary/TupleArbitrary';
 import { Random } from '../../../../../src/random/generator/Random';
 import { stream } from '../../../../../src/stream/Stream';
diff --git a/test/unit/check/arbitrary/helpers/BiasNumeric.spec.ts b/test/unit/check/arbitrary/helpers/BiasNumeric.spec.ts
deleted file mode 100644
index 0095717a..00000000
--- a/test/unit/check/arbitrary/helpers/BiasNumeric.spec.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import * as fc from '../../../../../lib/fast-check';
-
-import {
-  retrieveBiasRangesForNumeric,
-  integerLogLike,
-  bigIntLogLike,
-} from '../../../../../src/check/arbitrary/helpers/BiasNumeric';
-
-describe('BiasNumeric', () => {
-  describe('biasNumeric', () => {
-    it('Should bias close to extreme values and zero if min and max have opposite signs', () =>
-      fc.assert(
-        fc.property(fc.integer(Number.MIN_SAFE_INTEGER, -1), fc.integer(1, Number.MAX_SAFE_INTEGER), (min, max) => {
-          // Arrange / Act
-          const ranges = retrieveBiasRangesForNumeric(min, max, integerLogLike);
-
-          // Assert
-          expect(ranges).toHaveLength(3);
-          expect(ranges).toEqual([
-            { min: expect.toBeWithinRange(min, 0), max: expect.toBeWithinRange(0, max) }, // close to zero
-            { min: expect.toBeWithinRange(0, max), max: max }, // close to max
-            { min: min, max: expect.toBeWithinRange(min, 0) }, // close to min
-          ]);
-        })
-      ));
-
-    it('Should bias close to extreme values if min and max have same signs', () =>
-      fc.assert(
-        fc.property(
-          fc.constantFrom(1, -1),
-          fc.integer(0, Number.MAX_SAFE_INTEGER),
-          fc.integer(0, Number.MAX_SAFE_INTEGER),
-          (sign, minRaw, maxRaw) => {
-            // Arrange
-            fc.pre(minRaw !== maxRaw);
-            const minRawSigned = sign * minRaw;
-            const maxRawSigned = sign * maxRaw;
-            const [min, max] =
-              minRawSigned < maxRawSigned ? [minRawSigned, maxRawSigned] : [maxRawSigned, minRawSigned];
-
-            // Act
-            const ranges = retrieveBiasRangesForNumeric(min, max, integerLogLike);
-
-            // Assert
-            expect(ranges).toHaveLength(2);
-            const closeToMin = { min: expect.toBeWithinRange(min + 1, max), max: max }; // close to max
-            const closeToMax = { min: min, max: expect.toBeWithinRange(min, max - 1) }; // close to min
-            if (sign > 0) expect(ranges).toEqual([closeToMax, closeToMin]);
-            else expect(ranges).toEqual([closeToMin, closeToMax]);
-          }
-        )
-      ));
-
-    it('Should not bias anything for equal values of min and max', () =>
-      fc.assert(
-        fc.property(fc.maxSafeInteger(), (minMax) => {
-          // Arrange / Act
-          const ranges = retrieveBiasRangesForNumeric(minMax, minMax, integerLogLike);
-
-          // Assert
-          expect(ranges).toHaveLength(1);
-          expect(ranges).toEqual([{ min: minMax, max: minMax }]); // no bias, cannot do more
-        })
-      ));
-
-    it('Should always bias in valid ranges when using integerLogLike', () =>
-      fc.assert(
-        fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), (a, b) => {
-          // Arrange
-          const min = a < b ? a : b;
-          const max = a < b ? b : a;
-
-          // Act
-          const ranges = retrieveBiasRangesForNumeric(min, max, integerLogLike);
-
-          // Assert
-          expect(ranges).not.toHaveLength(0);
-          for (const range of ranges) {
-            expect(range.max).toBeGreaterThanOrEqual(range.min);
-            expect(min).toBeLessThanOrEqual(range.max);
-            expect(max).toBeGreaterThanOrEqual(range.max);
-            expect(min).toBeLessThanOrEqual(range.min);
-            expect(max).toBeGreaterThanOrEqual(range.min);
-          }
-        })
-      ));
-
-    if (typeof BigInt !== 'undefined') {
-      it('Should always bias in valid ranges when using bigIntLogLike', () =>
-        fc.assert(
-          fc.property(fc.bigInt(), fc.bigInt(), (a, b) => {
-            // Arrange
-            const min = a < b ? a : b;
-            const max = a < b ? b : a;
-
-            // Act
-            const ranges = retrieveBiasRangesForNumeric(min, max, bigIntLogLike);
-
-            // Assert
-            expect(ranges).not.toHaveLength(0);
-            for (const range of ranges) {
-              expect(range.max).toBeGreaterThanOrEqual(range.min);
-              expect(min).toBeLessThanOrEqual(range.max);
-              expect(max).toBeGreaterThanOrEqual(range.max);
-              expect(min).toBeLessThanOrEqual(range.min);
-              expect(max).toBeGreaterThanOrEqual(range.min);
-            }
-          })
-        ));
-    }
-  });
-});
-
-// Helpers
-
-expect.extend({
-  toBeWithinRange(received, floor, ceiling): jest.CustomMatcherResult {
-    const pass = received >= floor && received <= ceiling && !Number.isNaN(received);
-    return {
-      message: () => `expected ${received} ${pass ? 'not ' : ''} to be within range ${floor} - ${ceiling}`,
-      pass,
-    };
-  },
-});
-
-declare global {
-  // eslint-disable-next-line @typescript-eslint/no-namespace
-  namespace jest {
-    interface Expect {
-      toBeWithinRange(a: number, b: number): CustomMatcherResult;
-    }
-  }
-}
diff --git a/test/unit/check/model/commands/CommandsArbitrary.spec.ts b/test/unit/check/model/commands/CommandsArbitrary.spec.ts
index 182aa373..9da763c2 100644
--- a/test/unit/check/model/commands/CommandsArbitrary.spec.ts
+++ b/test/unit/check/model/commands/CommandsArbitrary.spec.ts
@@ -6,7 +6,7 @@ import { Random } from '../../../../../src/random/generator/Random';
 import { constant } from '../../../../../src/check/arbitrary/ConstantArbitrary';
 import { commands } from '../../../../../src/check/model/commands/CommandsArbitrary';
 import { genericTuple } from '../../../../../src/check/arbitrary/TupleArbitrary';
-import { nat } from '../../../../../src/check/arbitrary/IntegerArbitrary';
+import { nat } from '../../../../../src/arbitrary/nat';
 import { Arbitrary } from '../../../../../src/check/arbitrary/definition/Arbitrary';
 import { Shrinkable } from '../../../../../src/check/arbitrary/definition/Shrinkable';