Skip to content

Commit e8c1cb9

Browse files
committed
Support random number generation for BigInt.
1 parent 8fa596a commit e8c1cb9

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 2.4.1 (2022-01-04)
4+
- Support random number generation for BigInt
5+
- Migrated project to Swift 5.5 and Xcode 13.2
6+
37
## 2.4.0 (2021-05-12)
48
- Several enhancements of the `Complex` type
59
- Migrated project to Swift 5.4 and Xcode 12.5

Sources/NumberKit/BigInt.swift

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public struct BigInt: Hashable,
180180
self.init(words: y.uwords, negative: value < 0.0)
181181
}
182182
}
183-
183+
184184
/// Creates a `BigInt` from a sequence of digits for a given base. The first digit in the
185185
/// array of digits is the least significant one. `negative` is used to indicate negative
186186
/// `BigInt` numbers.
@@ -254,6 +254,26 @@ public struct BigInt: Hashable,
254254
self.init(digits: temp, negative: negative, base: base)
255255
}
256256

257+
/// Initializes a `BigInt` randomly with a given number of bits
258+
public init<R: RandomNumberGenerator>(randomWithMaxBits bitWidth: Int,
259+
using generator: inout R) {
260+
var words = ContiguousArray<UInt32>()
261+
let capacity = (bitWidth + UInt32.bitWidth - 1)/UInt32.bitWidth
262+
if capacity > 2 {
263+
words.reserveCapacity(capacity)
264+
}
265+
var bits = bitWidth
266+
while bits >= UInt32.bitWidth {
267+
words.append(generator.next())
268+
bits -= UInt32.bitWidth
269+
}
270+
if bits > 0 {
271+
let mask: UInt32 = (1 << bits) - 1
272+
words.append((generator.next() as UInt32) & mask)
273+
}
274+
self.init(words: words, negative: false)
275+
}
276+
257277
/// Converts the `BigInt` object into a string using the given base. `BigInt.DEC` is
258278
/// used as the default base.
259279
public func toString(base: Base = BigInt.decBase) -> String {
@@ -930,6 +950,39 @@ public struct BigInt: Hashable,
930950
}
931951
return BigInt.fromTwoComplement(&words)
932952
}
953+
954+
/// Returns a random `BigInt` with up to `bitWidth` bits using the random number
955+
/// generator `generator`.
956+
public static func random<R: RandomNumberGenerator>(withMaxBits bitWidth: Int,
957+
using generator: inout R) -> BigInt {
958+
return BigInt(randomWithMaxBits: bitWidth, using: &generator)
959+
}
960+
961+
/// Returns a random `BigInt` with up to `bitWidth` bits using the system random number
962+
/// generator.
963+
public static func random(withMaxBits bitWidth: Int) -> BigInt {
964+
var generator = SystemRandomNumberGenerator()
965+
return BigInt(randomWithMaxBits: bitWidth, using: &generator)
966+
}
967+
968+
/// Returns a random `BigInt` below the given upper bound `bound` using the random number
969+
/// generator `generator`.
970+
public static func random<R: RandomNumberGenerator>(below bound: BigInt,
971+
using generator: inout R) -> BigInt {
972+
let bitWidth = bound.bitSize
973+
var res = BigInt(randomWithMaxBits: bitWidth, using: &generator)
974+
while res >= bound {
975+
res = BigInt(randomWithMaxBits: bitWidth, using: &generator)
976+
}
977+
return res
978+
}
979+
980+
/// Returns a random `BigInt` below the given upper bound `bound` using the system random
981+
/// number generator.
982+
public static func random(below bound: BigInt) -> BigInt {
983+
var generator = SystemRandomNumberGenerator()
984+
return BigInt.random(below: bound, using: &generator)
985+
}
933986
}
934987

935988

Tests/NumberKitTests/BigIntTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,21 @@ class BigIntTests: XCTestCase {
342342
XCTAssertEqual(x7.words, [0, 1, 0])
343343
}
344344

345+
func testRandom() {
346+
let rnd1 = BigInt.random(withMaxBits: 218)
347+
XCTAssert(rnd1.bitCount <= 218)
348+
XCTAssert(rnd1.bitSize < 218 + UInt32.bitWidth)
349+
let rnd2 = BigInt.random(withMaxBits: 22)
350+
XCTAssert(rnd2.bitCount <= 22)
351+
XCTAssert(rnd2.bitSize < 22 + UInt32.bitWidth)
352+
let bound: BigInt = "9856024857249581231765137423436847588346498948545927456"
353+
let rnd3 = BigInt.random(below: bound)
354+
XCTAssert(rnd3 < bound)
355+
let bound2: BigInt = "123123"
356+
let rnd4 = BigInt.random(below: bound2)
357+
XCTAssert(rnd4 < bound2)
358+
}
359+
345360
func testDescription() {
346361
let x1s = "1234"
347362
let x1n = BigInt(stringLiteral: x1s)

0 commit comments

Comments
 (0)