Skip to content

Commit

Permalink
The magic Divider<T> constants README.md section (#114).
Browse files Browse the repository at this point in the history
This patch also introduces a 2-by-1 convenience method to natural integers.
  • Loading branch information
oscbyspro committed Dec 16, 2024
1 parent 29b944f commit 770c0d4
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 7 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [The overpowered `BinaryInteger`](#overview-the-overpowered-binary-integer)
- [The `Fallible<T>` redemption arc](#overview-the-fallible-redemption-arc)
- [The precondition `Guarantee` types](#overview-the-precondition-guarantee-types)
- [The magic `Divider<T>` constants](#overview-the-magic-divider-constants)

<a name="prelude"/>

Expand Down Expand Up @@ -272,3 +273,27 @@ init(_:) // error: precondition
init(unchecked:) // error: assert
init(unsafe:) // error: %%%%%%
```

<a name="overview-the-magic-divider-constants"/>

### The magic `Divider<T>` constants

You know how the compiler sometimes replaces division with multiplication, right? Great, now it is your turn to be a wizard! `Divider<T>` and `Divider21<T>` find magic constants that let us perform divisions using multiplication, addition, and shifts. Note that the latter divides numbers twice the size of the divisor.

```swift
let random = U8.random()
let divisor = Nonzero(U8.random(in: 1...255))
let divider = Divider(divisor)
let typical = random.division(divisor) as Division<U8, U8> // div
let magical = random.division(divider) as Division<U8, U8> // mul-add-shr
precondition(typical == magical) // quotient and remainder
```

```swift
let random = Doublet(low: U8.random(), high: U8.random())
let divisor = Nonzero(U8.random(in: 1...255))
let divider = Divider21(divisor)
let typical = U8.division(random, by: divisor) as Fallible<Division<U8, U8>>
let magical = U8.division(random, by: divider) as Fallible<Division<U8, U8>>
precondition(typical == magical) // quotient, remainder, and error indicator
```
17 changes: 17 additions & 0 deletions Sources/CoreKit/BinaryInteger+Division.swift
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,23 @@ extension BinaryInteger where Self: SystemsInteger & UnsignedInteger {
@inlinable public consuming func division(_ divider: borrowing Divider<Self>) -> Division<Self, Self> {
divider.division(dividing: self)
}

//=------------------------------------------------------------------------=
// MARK: Transformations x Divider x 2-by-1
//=------------------------------------------------------------------------=

/// Returns the `quotient`, `remainder` and `error` of dividing the `dividend` by the `divider`.
///
/// ### Division of 2 by 1
///
/// - Note: The `error` is set if the operation is `lossy`.
///
@inlinable public static func division(
_ dividend: consuming Doublet<Self>,
by divider: borrowing Divider21<Self>
) -> Fallible<Division<Self, Self>> {
divider.division(dividing: dividend)
}
}

//=----------------------------------------------------------------------------=
Expand Down
7 changes: 6 additions & 1 deletion Sources/CoreKit/BinaryInteger+Systems.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public protocol SystemsInteger<BitPattern>: EdgyInteger, FiniteInteger where Mag
/// Returns the byte swapped version of `self`.
@inlinable consuming func reversed(_ type: U8.Type) -> Self

/// Returns the result of dividing the `dividend` by the `divisor`.
/// Returns the `quotient`, `remainder` and `error` of dividing the `dividend` by the `divisor`.
///
/// ### Division of 2 by 1
///
/// - Note: The `error` is set if the operation is `lossy`.
///
@inlinable static func division(_ dividend: consuming Doublet<Self>, by divisor: borrowing Nonzero<Self>) -> Fallible<Division<Self, Self>>
}
37 changes: 37 additions & 0 deletions Tests/UltimathnumTests/BinaryInteger+Division.swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,43 @@ import TestKit
}
}

//*============================================================================*
// MARK: * Binary Integer x Division x Conveniences x 2 by 1
//*============================================================================*

@Suite struct BinaryIntegerTestsOnDivisionConveniences21 {

//=------------------------------------------------------------------------=
// MARK: Tests x Natural
//=------------------------------------------------------------------------=

@Test(
"BinaryInteger/division/conveniences/2-by-1: as NaturalInteger",
Tag.List.tags(.forwarding, .generic, .random),
arguments: typesAsSystemsIntegerAsUnsigned, fuzzers
) func asNaturalInteger(
type: any SystemsIntegerAsUnsigned.Type, randomness: consuming FuzzerInt
) throws {

try whereIs(type)
func whereIs<T>(_ type: T.Type) throws where T: SystemsIntegerAsUnsigned {
for _ in 0 ..< 32 {
let low = T.entropic(using: &randomness)
let high = T.entropic(using: &randomness)
let dividend = Doublet(low: low, high: high)
let divisor = T.entropic(using: &randomness)

guard let divisor = Nonzero(exactly: divisor) else { continue }
let divider = Divider21(divisor) as Divider21 as Divider21 as Divider21

let typical: Fallible = T.division(dividend, by: divisor)
let magical: Fallible = T.division(dividend, by: divider)
try #require(typical == magical)
}
}
}
}

//*============================================================================*
// MARK: * Binary Integer x Division x Open Source Issues
//*============================================================================*
Expand Down
36 changes: 30 additions & 6 deletions Tests/UltimathnumTests/Divider+Documentation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,35 @@ import TestKit
//=------------------------------------------------------------------------=

@Test("README") func readme() {
let random = U8.random()
let divisor = Nonzero(U8.random(in: 1...255))
let divider = Divider(divisor.value)
let typical = random.division(divisor) as Division<U8, U8> // div
let magical = random.division(divider) as Division<U8, U8> // mul-add-shr
precondition(typical == magical) // quotient and remainder
for _ in 0 ..< 8 {
let random = U8.random()
let divisor = Nonzero(U8.random(in: 1...255))
let divider = Divider(divisor)
let typical = random.division(divisor) as Division<U8, U8> // div
let magical = random.division(divider) as Division<U8, U8> // mul-add-shr
precondition(typical == magical) // quotient and remainder
}
}
}

//*============================================================================*
// MARK: * Divider x Documentation x 2-by-1
//*============================================================================*

@Suite struct DividerTestsOnDocumentation21 {

//=------------------------------------------------------------------------=
// MARK: Tests
//=------------------------------------------------------------------------=

@Test("README") func readme() {
for _ in 0 ..< 8 {
let random = Doublet(low: U8.random(), high: U8.random())
let divisor = Nonzero(U8.random(in: 1...255))
let divider = Divider21(divisor)
let typical = U8.division(random, by: divisor) as Fallible<Division<U8, U8>>
let magical = U8.division(random, by: divider) as Fallible<Division<U8, U8>>
precondition(typical == magical) // quotient, remainder, and error indicator
}
}
}

0 comments on commit 770c0d4

Please sign in to comment.