Skip to content

Commit

Permalink
Update tests to latest version.
Browse files Browse the repository at this point in the history
  • Loading branch information
mgriebling committed Aug 19, 2024
1 parent 91c3809 commit a3909b3
Show file tree
Hide file tree
Showing 23 changed files with 718 additions and 358 deletions.
Binary file not shown.
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import PackageDescription

let package = Package(
name: "BigInt",
platforms: [
.macOS("13.3"), .iOS("16.4"), .tvOS("16.4"), .watchOS("9.4")
// .iPadOS("18.0)"), //.macCatalyst("13.0")
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
Expand Down
45 changes: 30 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
# BigInt

The BigInt package provides arbitrary-precision integer arithmetic in Swift.
Now supports **StaticBigInt** so you can do stuff like:

```Swift
let x = BInt(123456789012345678901234567890123456789012345678901234567890)
```
String literals are now optional! Some tests now use **StaticBigInt** initalizers.

Its functionality falls in the following categories:

- Performance:
* **Arithmetic:** add, subtract, multiply, divide, remainder and exponentiation
* **Comparison:** the six standard operations == != < <= > >=
* **Shifting:** logical left shift and rigth shift
* **Logical:** bitwise and, or, xor, and not
* **Modulo:** normal modulus, inverse modulus, and modular exponentiation
* **Conversion:** to double, to integer, to string, to magnitude byte array, and to 2's complement byte array
* **Primes:** prime number testing, probable prime number generation and primorial
* **Miscellaneous:** random number generation, greatest common divisor, least common multiple, n-th root, square root modulo an odd prime, Jacobi symbol, Kronecker symbol, Factorial function, Binomial function, Fibonacci numbers, Lucas numbers and Bernoulli numbers
* **Fractions:** Standard arithmetic on fractions whose numerators and denominators are of unbounded size
* **Chinese Remainder Theorem:** Compute the CRT value from given residues and moduli

BigInt requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types.
It needs to run on macOS 13.3+, iOS 16.4+, tvOS 16.4+, watchOS 9.4+.
BigInt has been updated to include Leif Ibsen BigInt changes up to v1.19.0.

## Performance:

- Division 2x AttaSwift
- Multiplication 7x AttaSwift
- Logic functions 2x AttaSwift
- Convert to String 3x AttaSwift
- Shifts up to 16x AttaSwift
- Arithmetic: add, subtract, multiply, divide, remainder and exponentiation
- Comparison: the six standard operations == != < <= > >=
- Shifting: logical left shift and rigth shift
- Logical: bitwise and, or, xor, and not
- Modulo: normal modulus, inverse modulus, and modular exponentiation
- Conversion: to double, to integer, to string, to magnitude byte array, and to 2's complement byte array
- Primes: prime number testing, probable prime number generation and primorial
- Miscellaneous: random number generation, greatest common divisor, least common multiple, n-th root, square root modulo an odd prime, Jacobi symbol, Kronecker symbol, Factorial function, Binomial function, Fibonacci numbers, Lucas numbers and Bernoulli numbers
- Fractions: Standard arithmetic on fractions whose numerators and denominators are of unbounded size

## Protocol support

- Added `SignedInteger`, `BinaryInteger`, and `Numeric` protocol compliance.
- Optional support for `StaticBigInt` to allow `BigInt` number initialization
from very large integer literals. Uncomment the `BigInt-Extensions`
`StaticBigInt` support.
- Support for `StaticBigInt` to allow `BigInt` number initialization
from very large integer literals.

Why support protocols? By supporting them you have the ability to
formulate generic algorithms and make use of algorithms from others
Expand All @@ -40,8 +53,6 @@ Its functionality falls in the following categories:
In addition, if a third party defines extensions for the supported protocols,
these can be easily adapted by just conforming to that protocol.

BigInt requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types.

## Usage
In your projects Package.swift file add a dependency like

Expand All @@ -65,6 +76,10 @@ dependencies: [
let b = BInt("123456789012345678901234567890")!
let c = BInt("1234567890abcdef1234567890abcdef", radix: 16)!

// From integer literals
let b = BInt(123456789012345678901234567890)
let c = BInt(0x1234567890abcdef1234567890abcdef)

// From magnitude and sign
let m: Limbs = [1, 2, 3]
let d = BInt(m) // d = 1020847100762815390427017310442723737601
Expand Down
91 changes: 90 additions & 1 deletion Sources/BigInt/BigFrac.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,39 @@ public struct BFraction: CustomStringConvertible, Comparable, Equatable, Sendabl
self.init(m * (BInt.TEN ** e), BInt.ONE)
}
}

/// Constructs a BFraction from a continued fraction - `BInt` version
///
/// - Precondition: `x` contains at least one element, all elements except possibly the first are positive
/// - Parameters:
/// - x: The continued fraction
/// - Returns: The BFraction represented by `x`
public init(_ x: [BInt]) {
precondition(x.count > 0)
var numerator = BInt.ZERO
var denominator = BInt.ONE
for i in (1 ..< x.count).reversed() {
precondition(x[i].isPositive)
numerator += x[i] * denominator
(numerator, denominator) = (denominator, numerator)
}
numerator += x[0] * denominator
self.init(numerator, denominator)
}

/// Constructs a BFraction from a continued fraction - `Int` version
///
/// - Precondition: `x` contains at least one element, all elements except possibly the first are positive
/// - Parameters:
/// - x: The continued fraction
/// - Returns: The BFraction represented by `x`
public init(_ x: [Int]) {
var bx = [BInt](repeating: BInt.ZERO, count: x.count)
for i in 0 ..< bx.count {
bx[i] = BInt(x[i])
}
self.init(bx)
}


// MARK: Stored properties
Expand Down Expand Up @@ -356,6 +389,26 @@ public struct BFraction: CustomStringConvertible, Comparable, Equatable, Sendabl
}
return d
}

///
/// - Returns: `self` as a Continued Fraction
public func asContinuedFraction() -> [BInt] {
var numerator = self.numerator
var denominator = self.denominator
var (q, r) = numerator.quotientAndRemainder(dividingBy: denominator)
var x = [q]
if self.isNegative {
x[0] -= 1
numerator += (1 - x[0]) * denominator
r += denominator
}
while r.isNotZero {
(numerator, denominator) = (denominator, r)
(q, r) = numerator.quotientAndRemainder(dividingBy: denominator)
x.append(q)
}
return x
}


// MARK: Addition functions
Expand Down Expand Up @@ -460,6 +513,11 @@ public struct BFraction: CustomStringConvertible, Comparable, Equatable, Sendabl
return BFraction(-x.numerator, x.denominator)
}

/// Negates `self`
public mutating func negate() {
self.numerator.negate()
}

/// Subtraction
///
/// - Parameters:
Expand Down Expand Up @@ -1176,5 +1234,36 @@ public struct BFraction: CustomStringConvertible, Comparable, Equatable, Sendabl
}
return x
}


// - Precondition: n > 0
/// - Parameters:
/// - n: The number of fractions to add
/// - Returns: The n'th harmonic number
public static func harmonic(_ n: Int) -> BFraction {
precondition(n > 0)
return _harmonic(1, n)
}

static func _harmonic(_ a: Int, _ b: Int) -> BFraction {
if a == b {
return BFraction(1, a)
}
let m = (a + b) >> 1
return _harmonic(a, m) + _harmonic(m + 1, b)
}

/// Harmonic sequence: The first n harmonic numbers
///
/// - Precondition: n > 0
/// - Parameters:
/// - n: The number of harmonic numbers
/// - Returns: The harmonic numbers: H1, H2 ... Hn
public static func harmonicSequence(_ n: Int) -> [BFraction] {
precondition(n > 0)
var x = [BFraction](repeating: BFraction.ONE, count: n)
for i in 1 ..< n {
x[i] = x[i - 1] + BFraction(1, i + 1)
}
return x
}
}
53 changes: 24 additions & 29 deletions Sources/BigInt/BigInt-Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
extension BInt : SignedInteger {
public static var isSigned: Bool { true }

public init(integerLiteral value: Int) {
self.init(value)
}

public init<T>(_ source: T) where T : BinaryInteger {
if let int = BInt(exactly: source) {
self = int
Expand Down Expand Up @@ -90,6 +86,9 @@ extension BInt : Numeric {
}

extension BInt : BinaryInteger {

public typealias Words = [UInt]

public static func <<= <RHS:BinaryInteger>(lhs: inout BInt, rhs: RHS) {
lhs = lhs << Int(rhs)
}
Expand All @@ -99,28 +98,24 @@ extension BInt : BinaryInteger {
}
}

/// Add support for `StaticBigInt` - 24 Jun 2023 - MG
/// Currently disabled due to Swift Playground incompatiblity
/// Uncomment to enable `StaticBigInt` support (i.e., huge integer literals).
//@available(macOS 13.3, *)
//extension BInt : ExpressibleByIntegerLiteral {
// public init(integerLiteral value: StaticBigInt) {
// let isNegative = value.signum() < 0
// let bitWidth = value.bitWidth
// if bitWidth < Int.bitWidth {
// self.init(Int(bitPattern: value[0]))
// } else {
// precondition(value[0].bitWidth == 64, "Requires 64-bit Ints!")
// let noOfWords = (bitWidth / 64) + 1 // must be 64-bit system
// var words = Limbs()
// for index in 0..<noOfWords {
// // StaticBigInt words are 2's complement so negative
// // values needed to be inverted and have one added
// if isNegative { words.append(UInt64(~value[index])) }
// else { words.append(UInt64(value[index])) }
// }
// self.init(words, false)
// if isNegative { self += 1; self.negate() }
// }
// }
//}
extension BInt : ExpressibleByIntegerLiteral {
public init(integerLiteral value: StaticBigInt) {
let isNegative = value.signum() < 0
let bitWidth = value.bitWidth
if bitWidth < Int.bitWidth {
self.init(Int(bitPattern: value[0]))
} else {
precondition(value[0].bitWidth == 64, "Requires 64-bit Ints!")
let noOfWords = (bitWidth / 64) + 1 // must be 64-bit system
var words = Limbs()
for index in 0..<noOfWords {
// StaticBigInt words are 2's complement so negative
// values needed to be inverted and have one added
if isNegative { words.append(~value[index]) }
else { words.append(value[index]) }
}
self.init(words, false)
if isNegative { self += 1; self.negate() }
}
}
}
Loading

0 comments on commit a3909b3

Please sign in to comment.