I wanted to fuzz something, so I've added a new module and some randomness features:
.product(name: "Ultimathnum", package: "Ultimathnum"), // umbrella
.product(name: "CoreKit", package: "Ultimathnum"),
.product(name: "DoubleIntKit", package: "Ultimathnum"),
.product(name: "FibonacciKit", package: "Ultimathnum"),
.product(name: "InfiniIntKit", package: "Ultimathnum"),
.product(name: "RandomIntKit", package: "Ultimathnum"), // oh, so shiny!
.product(name: "StdlibIntKit", package: "Ultimathnum"),
Random number generation is fully generic over BinaryInteger, so it also works with signed and unsigned arbitrary-precision integers:
extension Ultimathnum.BinaryInteger {
/// Generates a random value in the given `range` from the given source of `randomness`.
///
/// - Requires: The `range` must be finite.
///
public static func random(in range: ClosedRange<Self>, using randomness: inout some Randomness) -> Self { ... }
/// Generates a random value in the given `range` from the given source of `randomness`.
///
/// - Requires: The `range` must be finite.
///
public static func random(in range: Range<Self>, using randomness: inout some Randomness) -> Optional<Self> { ... }
/// Generates random bits through the given `index`.
///
/// Signed integers are extended by the most significant bit whereas unsigned
/// integers are extended by zero. You may bit-cast a different type to adopt
/// its behavior.
///
/// ┌──────────┬──────────┬──────────┐
/// │ index: 0 │ index: 1 │ index: 2 │
/// ┌──────────┼──────────┤──────────┤──────────┤
/// │ Signed │ -1 ... 0 │ -2 ... 1 │ -4 ... 3 │
/// ├──────────┼──────────┤──────────┤──────────┤
/// │ Unsigned │ 0 ... 1 │ 0 ... 3 │ 0 ... 7 │
/// └──────────┴──────────┴──────────┴──────────┘
///
/// - Note: The result is always finite.
///
/// - Requires: The request must not exceed the entropy limit.
///
public static func random(through index: Shift<Magnitude>, using randomness: inout some Randomness) -> Self { ... }
}
Arbitrary integers and systems integers derive different algorithms, which is possible because I've hoisted 1-by-1-as-2 multiplication to BinaryInteger:
U32.max.times(U32.max) // value: 1, error: true
UXL.max.times(UXL.max) // value: 1, error: true
U32.max.multiplication(U32.max) // low: 1, high: ~1
UXL.max.multiplication(UXL.max) // low: 1, high: ~1
It turns out that computing the high part of multiplication is trivial in both the signed and the unsigned case, making the latter even more infinite! Lol.