Skip to content

Commit

Permalink
Release 1.4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Jun 18, 2022
1 parent 37c1c43 commit 1536608
Show file tree
Hide file tree
Showing 20 changed files with 463 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ BigInt requires Swift 5.0. It also requires that the Int and UInt types be 64 bi
In your projects Package.swift file add a dependency like<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.4.1"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.4.3"),
]

<h2><b>Examples</b></h2>
Expand Down
100 changes: 86 additions & 14 deletions Sources/BigInt/BigInt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,28 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
/// - x: Left hand addend
/// - y: Right hand addend
public static func +=(x: inout BInt, y: Int) {
x += BInt(y)

// Much better performance than simply
// x += BInt(y)

if y > 0 {
if x.isNegative {
if x.magnitude.difference(Limb(y)) <= 0 {
x.setSign(false)
}
} else {
x.magnitude.add(Limb(y))
}
} else if y < 0 {
let yy = y == Int.min ? 0x8000000000000000 : Limb(-y)
if x.isNegative {
x.magnitude.add(yy)
} else {
if x.magnitude.difference(yy) < 0 {
x.setSign(true)
}
}
}
}


Expand Down Expand Up @@ -844,7 +865,28 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
/// - x: Left hand minuend
/// - y: Right hand subtrahend
public static func -=(x: inout BInt, y: Int) {
x -= BInt(y)

// Much better performance than simply
// x -= BInt(y)

if y > 0 {
if x.isNegative {
x.magnitude.add(Limb(y))
} else {
if x.magnitude.difference(Limb(y)) < 0 {
x.setSign(true)
}
}
} else if y < 0 {
let yy = y == Int.min ? 0x8000000000000000 : Limb(-y)
if x.isPositive {
x.magnitude.add(yy)
} else {
if x.magnitude.difference(yy) <= 0 {
x.setSign(false)
}
}
}
}


Expand Down Expand Up @@ -922,32 +964,63 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
/// Division
///
/// - Precondition: Divisor is not zero
/// - Parameter x: Divisor
/// - Parameter x: Divisor - a BInt value
/// - Returns: Quotient and remainder of *self* / x
public func quotientAndRemainder(dividingBy x: BInt) -> (quotient: BInt, remainder: BInt) {
var quotient = BInt.ZERO
var remainder = BInt.ZERO
self.quotientAndRemainder(dividingBy: x, &quotient, &remainder)
if x.magnitude.count > Limbs.BZ_DIV_LIMIT && self.magnitude.count > x.magnitude.count + Limbs.BZ_DIV_LIMIT {
(quotient.magnitude, remainder.magnitude) = self.magnitude.bzDivMod(x.magnitude)
} else {
(quotient.magnitude, remainder.magnitude) = self.magnitude.divMod(x.magnitude)
}
quotient.setSign(self.isNegative != x.isNegative)
remainder.setSign(self.isNegative)
return (quotient, remainder)
}

/// Division
///
/// - Precondition: Divisor is not zero
/// - Parameters:
/// - x: Divisor
/// - x: Divisor - a BInt value
/// - quotient: Set to the quotient of *self* / x
/// - remainder: Set to the remainder of *self* / x
public func quotientAndRemainder(dividingBy x: BInt, _ quotient: inout BInt, _ remainder: inout BInt) {
if x.magnitude.count > Limbs.BZ_DIV_LIMIT && self.magnitude.count > x.magnitude.count + Limbs.BZ_DIV_LIMIT {
self.magnitude.bzDivMod(x.magnitude, &quotient.magnitude, &remainder.magnitude)
(quotient, remainder) = self.quotientAndRemainder(dividingBy: x)
}

/// Division
///
/// - Precondition: Divisor is not zero
/// - Parameter x: Divisor - an Int value
/// - Returns: Quotient and remainder of *self* / x
public func quotientAndRemainder(dividingBy x: Int) -> (quotient: BInt, remainder: Int) {
var divisor: Limb
if x < 0 {
divisor = x == Int.min ? 0x8000000000000000 : Limb(-x)
} else {
self.magnitude.divMod(x.magnitude, &quotient.magnitude, &remainder.magnitude)
divisor = Limb(x)
}
quotient.setSign(self.isNegative != x.isNegative)
remainder.setSign(self.isNegative)
var quotient = BInt.ZERO
var r: Limb
(quotient.magnitude, r) = self.magnitude.divMod(divisor)
quotient.setSign(self.isNegative && x > 0 || self.isPositive && x < 0)
let remainder = self.isNegative ? -Int(r) : Int(r)
return (quotient, remainder)
}


/// Division
///
/// - Precondition: Divisor is not zero
/// - Parameters:
/// - x: Divisor - an Int value
/// - quotient: Set to the quotient of *self* / x
/// - remainder: Set to the remainder of *self* / x
public func quotientAndRemainder(dividingBy x: Int, _ quotient: inout BInt, _ remainder: inout Int) {
(quotient, remainder) = self.quotientAndRemainder(dividingBy: x)
}

/// Division
///
/// - Precondition: Divisor is not zero
Expand Down Expand Up @@ -978,7 +1051,7 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
/// - y: Divisor
/// - Returns: x / y
public static func /(x: BInt, y: Int) -> BInt {
return x / BInt(y)
return x.quotientAndRemainder(dividingBy: y).quotient
}

/// x = x / y
Expand Down Expand Up @@ -1077,7 +1150,6 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
/// - Parameter x: Divisor
/// - Returns: *self* *mod* x, a non-negative value
public func mod(_ x: Int) -> Int {
precondition(x != 0, "Division by zero")
if x == Int.min {
let r = Int(self.magnitude[0] & 0x7fffffffffffffff)
return self.isNegative && r > 0 ? -(Int.min + r) : r
Expand Down Expand Up @@ -1831,7 +1903,7 @@ public struct BInt: CustomStringConvertible, Comparable, Equatable, Hashable {
return nil
}
let A = self % p
switch (p % 8).asInt() {
switch p.mod(8) {
case 3, 7:
return A.expMod((p + 1) >> 2, p)

Expand Down
6 changes: 4 additions & 2 deletions Sources/BigInt/BurnikelZiegler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ extension Array where Element == Limb {
/*
* [BURNIKEL] - algorithm 3
*/
func bzDivMod(_ v: Limbs, _ quotient: inout Limbs, _ remainder: inout Limbs) {
func bzDivMod(_ v: Limbs) -> (quotient: Limbs, remainder: Limbs) {
var quotient: Limbs = [0]
var remainder: Limbs = []
var A = self
var B = v
let s = B.count
Expand All @@ -26,7 +28,6 @@ extension Array where Element == Limb {
A.shiftLeft(sigma)
B.shiftLeft(sigma)
let t = Swift.max(2, (A.bitWidth + n64) / n64)
quotient = [0]
var Z = Limbs(repeating: 0, count: 2 * n)
var from = (t - 1) * n
var zi = n
Expand Down Expand Up @@ -62,6 +63,7 @@ extension Array where Element == Limb {
remainder.shiftRight(sigma)
}
}
return (quotient, remainder)
}

/*
Expand Down
20 changes: 6 additions & 14 deletions Sources/BigInt/Limbs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -599,24 +599,15 @@ extension Array where Element == Limb {
}

// Limbs / Limbs => (quotient: Limbs, remainder: Limbs)
func divMod(_ v: Limbs) -> (quotient: Limbs, remainder: Limbs) {
var quotient = Limbs()
var remainder = Limbs()
self.divMod(v, &quotient, &remainder)
return (quotient, remainder)
}

// [KNUTH] - chapter 4.3.1, algorithm D
func divMod(_ v: Limbs, _ quotient: inout Limbs, _ remainder: inout Limbs) {
func divMod(_ v: Limbs) -> (quotient: Limbs, remainder: Limbs) {
if self.lessThan(v) {
quotient = [0]
remainder = self
return ([0], self)
} else if v.count == 1 {
let (q, r) = self.divMod(v[0])
quotient = q
remainder = [r]
return (q, [r])
} else {
remainder = self
var remainder = self
var v = v
let n = v.count
let m = remainder.count
Expand All @@ -629,7 +620,7 @@ extension Array where Element == Limb {
var k = m - n
let vn1 = v[n - 1]
let vReciprocal = vn1.dividingFullWidth((0xffffffffffffffff - vn1, 0xffffffffffffffff)).quotient
quotient = Limbs(repeating: 0, count: k + 1)
var quotient = Limbs(repeating: 0, count: k + 1)
var ovfl: Bool
repeat {
if vn1 == remainder[k + n] {
Expand Down Expand Up @@ -659,6 +650,7 @@ extension Array where Element == Limb {
} while k >= 0
remainder.shiftRight(d)
quotient.normalize()
return (quotient, remainder)
}
}

Expand Down
32 changes: 32 additions & 0 deletions Tests/BigIntTests/AdditionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class AdditionTest: XCTestCase {
XCTAssertEqual((-7) + BInt(-4), BInt(-11))
XCTAssertEqual((-7) + BInt(0), BInt(-7))
XCTAssertEqual(7 + BInt(0), BInt(7))
XCTAssertEqual(0 + BInt(7), BInt(7))
XCTAssertEqual(0 + BInt(-7), BInt(-7))
XCTAssertEqual(0 + BInt(0), BInt(0))
}

func test2() {
Expand Down Expand Up @@ -77,4 +80,33 @@ class AdditionTest: XCTestCase {
}
}

func doTest1(_ x: BInt, _ y: Int) {
XCTAssertEqual(x + y, x + BInt(y))
XCTAssertEqual((-x) + y, (-x) + BInt(y))
if y != Int.min {
XCTAssertEqual(x + (-y), x + BInt(-y))
XCTAssertEqual((-x) + (-y), (-x) + BInt(-y))
}
}

func doTest2(_ x: BInt) {
doTest1(x, 0)
doTest1(x, 1)
doTest1(x, -1)
doTest1(x, Int.max)
doTest1(x, Int.min)
doTest1(x, Int.max - 1)
doTest1(x, Int.min + 1)
}

func test5() {
doTest2(BInt(bitWidth: 1000))
doTest2(BInt(0))
doTest2(BInt(1))
doTest2(BInt(-1))
doTest2(BInt(Int.max))
doTest2(-BInt(Int.max))
doTest2(BInt(Int.min))
doTest2(-BInt(Int.min))
}
}
4 changes: 2 additions & 2 deletions Tests/BigIntTests/DivModBZTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class DivModBZTest: XCTestCase {
var r1: Limbs = []
var q2: Limbs = []
var r2: Limbs = []
dividend.magnitude.divMod(divisor.magnitude, &q1, &r1)
dividend.magnitude.bzDivMod(divisor.magnitude, &q2, &r2)
(q1, r1) = dividend.magnitude.divMod(divisor.magnitude)
(q2, r2) = dividend.magnitude.bzDivMod(divisor.magnitude)
XCTAssertEqual(q1, q2)
XCTAssertEqual(r1, r2)
}
Expand Down
23 changes: 23 additions & 0 deletions Tests/BigIntTests/DivModTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class DivModTest: XCTestCase {
let r1 = x1 % x2
let q1 = x1 / x2
XCTAssertEqual(x1, x2 * q1 + r1)
XCTAssertTrue(r1.abs < x2.abs)
let (q2, r2) = x1.quotientAndRemainder(dividingBy: x2)
XCTAssertEqual(q1, q2)
XCTAssertEqual(r1, r2)
Expand All @@ -38,6 +39,16 @@ class DivModTest: XCTestCase {
XCTAssertEqual(x1.mod(Int.min), x1.mod(BInt(Int.min)).asInt()!)
}

func doTest5(_ x1: BInt, _ x2: Int) {
let (q1, r1) = x1.quotientAndRemainder(dividingBy: x2)
let (q2, r2) = x1.quotientAndRemainder(dividingBy: BInt(x2))
XCTAssertEqual(q1, q2)
XCTAssertEqual(r1, r2.asInt()!)
XCTAssertEqual(x1 / x2, x1 / BInt(x2))
XCTAssertEqual(x1 % x2, x1 % BInt(x2))
XCTAssertEqual(x1.mod(x2), x1.mod(BInt(x2)).asInt()!)
}

func test1() {
doTest1(30, 20)
doTest1(30, 120)
Expand Down Expand Up @@ -102,4 +113,16 @@ class DivModTest: XCTestCase {
}
}

func test5() {
let x = BInt(bitWidth: 1000)
doTest5(x, 1)
doTest5(x, -1)
doTest5(x, 10)
doTest5(x, -10)
doTest5(x, Int.max)
doTest5(x, Int.max - 1)
doTest5(x, Int.min)
doTest5(x, Int.min + 1)
}

}
34 changes: 33 additions & 1 deletion Tests/BigIntTests/SubtractionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class SubtractionTest: XCTestCase {
XCTAssertEqual((-7) - BInt(-4), BInt(-3))
XCTAssertEqual((-7) - BInt(0), BInt(-7))
XCTAssertEqual(7 - BInt(0), BInt(7))
XCTAssertEqual(0 - BInt(7), BInt(-7))
XCTAssertEqual(0 - BInt(-7), BInt(7))
XCTAssertEqual(0 - BInt(0), BInt(0))
}

func test2() {
Expand All @@ -51,7 +54,36 @@ class SubtractionTest: XCTestCase {
var x4 = BInt(-7)
x4 -= BInt(-4)
XCTAssertEqual(x4, BInt(-3))

}

func doTest1(_ x: BInt, _ y: Int) {
XCTAssertEqual(x - y, x - BInt(y))
XCTAssertEqual((-x) - y, (-x) - BInt(y))
if y != Int.min {
XCTAssertEqual(x - (-y), x - BInt(-y))
XCTAssertEqual((-x) - (-y), (-x) - BInt(-y))
}
}

func doTest2(_ x: BInt) {
doTest1(x, 0)
doTest1(x, 1)
doTest1(x, -1)
doTest1(x, Int.max)
doTest1(x, Int.min)
doTest1(x, Int.max - 1)
doTest1(x, Int.min + 1)
}

func test3() {
doTest2(BInt(bitWidth: 1000))
doTest2(BInt(0))
doTest2(BInt(1))
doTest2(BInt(-1))
doTest2(BInt(Int.max))
doTest2(-BInt(Int.max))
doTest2(BInt(Int.min))
doTest2(-BInt(Int.min))
}

}
2 changes: 1 addition & 1 deletion docs/Structs.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ <h4>Declaration</h4>
</section>
</section>
<section id="footer">
<p>&copy; 2022 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2022-06-09)</p>
<p>&copy; 2022 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2022-06-17)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.2</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
</section>
</article>
Expand Down
Loading

0 comments on commit 1536608

Please sign in to comment.