Skip to content

Commit

Permalink
Support random number generation for BigInt.
Browse files Browse the repository at this point in the history
  • Loading branch information
objecthub committed Jan 4, 2022
1 parent 8fa596a commit e8c1cb9
Showing 3 changed files with 73 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 2.4.1 (2022-01-04)
- Support random number generation for BigInt
- Migrated project to Swift 5.5 and Xcode 13.2

## 2.4.0 (2021-05-12)
- Several enhancements of the `Complex` type
- Migrated project to Swift 5.4 and Xcode 12.5
55 changes: 54 additions & 1 deletion Sources/NumberKit/BigInt.swift
Original file line number Diff line number Diff line change
@@ -180,7 +180,7 @@ public struct BigInt: Hashable,
self.init(words: y.uwords, negative: value < 0.0)
}
}

/// Creates a `BigInt` from a sequence of digits for a given base. The first digit in the
/// array of digits is the least significant one. `negative` is used to indicate negative
/// `BigInt` numbers.
@@ -254,6 +254,26 @@ public struct BigInt: Hashable,
self.init(digits: temp, negative: negative, base: base)
}

/// Initializes a `BigInt` randomly with a given number of bits
public init<R: RandomNumberGenerator>(randomWithMaxBits bitWidth: Int,
using generator: inout R) {
var words = ContiguousArray<UInt32>()
let capacity = (bitWidth + UInt32.bitWidth - 1)/UInt32.bitWidth
if capacity > 2 {
words.reserveCapacity(capacity)
}
var bits = bitWidth
while bits >= UInt32.bitWidth {
words.append(generator.next())
bits -= UInt32.bitWidth
}
if bits > 0 {
let mask: UInt32 = (1 << bits) - 1
words.append((generator.next() as UInt32) & mask)
}
self.init(words: words, negative: false)
}

/// Converts the `BigInt` object into a string using the given base. `BigInt.DEC` is
/// used as the default base.
public func toString(base: Base = BigInt.decBase) -> String {
@@ -930,6 +950,39 @@ public struct BigInt: Hashable,
}
return BigInt.fromTwoComplement(&words)
}

/// Returns a random `BigInt` with up to `bitWidth` bits using the random number
/// generator `generator`.
public static func random<R: RandomNumberGenerator>(withMaxBits bitWidth: Int,
using generator: inout R) -> BigInt {
return BigInt(randomWithMaxBits: bitWidth, using: &generator)
}

/// Returns a random `BigInt` with up to `bitWidth` bits using the system random number
/// generator.
public static func random(withMaxBits bitWidth: Int) -> BigInt {
var generator = SystemRandomNumberGenerator()
return BigInt(randomWithMaxBits: bitWidth, using: &generator)
}

/// Returns a random `BigInt` below the given upper bound `bound` using the random number
/// generator `generator`.
public static func random<R: RandomNumberGenerator>(below bound: BigInt,
using generator: inout R) -> BigInt {
let bitWidth = bound.bitSize
var res = BigInt(randomWithMaxBits: bitWidth, using: &generator)
while res >= bound {
res = BigInt(randomWithMaxBits: bitWidth, using: &generator)
}
return res
}

/// Returns a random `BigInt` below the given upper bound `bound` using the system random
/// number generator.
public static func random(below bound: BigInt) -> BigInt {
var generator = SystemRandomNumberGenerator()
return BigInt.random(below: bound, using: &generator)
}
}


15 changes: 15 additions & 0 deletions Tests/NumberKitTests/BigIntTests.swift
Original file line number Diff line number Diff line change
@@ -342,6 +342,21 @@ class BigIntTests: XCTestCase {
XCTAssertEqual(x7.words, [0, 1, 0])
}

func testRandom() {
let rnd1 = BigInt.random(withMaxBits: 218)
XCTAssert(rnd1.bitCount <= 218)
XCTAssert(rnd1.bitSize < 218 + UInt32.bitWidth)
let rnd2 = BigInt.random(withMaxBits: 22)
XCTAssert(rnd2.bitCount <= 22)
XCTAssert(rnd2.bitSize < 22 + UInt32.bitWidth)
let bound: BigInt = "9856024857249581231765137423436847588346498948545927456"
let rnd3 = BigInt.random(below: bound)
XCTAssert(rnd3 < bound)
let bound2: BigInt = "123123"
let rnd4 = BigInt.random(below: bound2)
XCTAssert(rnd4 < bound2)
}

func testDescription() {
let x1s = "1234"
let x1n = BigInt(stringLiteral: x1s)

0 comments on commit e8c1cb9

Please sign in to comment.