From 43c479b4c70568c955a27b8407d370648f1603f6 Mon Sep 17 00:00:00 2001 From: Yuta Koshizawa Date: Thu, 10 Dec 2020 04:58:58 +0900 Subject: [PATCH 1/5] Implement `BigInt` --- Sources/AtCoderSupport/BigInt.swift | 52 +++++++++ Tests/AtCoderSupportTests/BigIntTests.swift | 118 ++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 Sources/AtCoderSupport/BigInt.swift create mode 100644 Tests/AtCoderSupportTests/BigIntTests.swift diff --git a/Sources/AtCoderSupport/BigInt.swift b/Sources/AtCoderSupport/BigInt.swift new file mode 100644 index 0000000..2a4d522 --- /dev/null +++ b/Sources/AtCoderSupport/BigInt.swift @@ -0,0 +1,52 @@ +import Foundation +struct BigInt: AdditiveArithmetic, ExpressibleByIntegerLiteral, CustomStringConvertible { + private var decimal: Decimal + private init(_ decimal: Decimal) { + self.decimal = decimal + } + init(_ value: Int) { + decimal = .init(value) + } + init?(_ string: String) { + guard let decimal = Decimal(string: string, locale: Locale(identifier: "en")) else { return nil } + self.init(decimal) + } + init(integerLiteral value: Int) { + self.init(value) + } + static func +(lhs: BigInt, rhs: BigInt) -> BigInt { + BigInt(lhs.decimal + rhs.decimal) + } + static func -(lhs: BigInt, rhs: BigInt) -> BigInt { + BigInt(lhs.decimal - rhs.decimal) + } + static func *(lhs: BigInt, rhs: BigInt) -> BigInt { + BigInt(lhs.decimal * rhs.decimal) + } + static func /(lhs: BigInt, rhs: BigInt) -> BigInt { + BigInt((lhs.decimal / rhs.decimal).roundToZero) + } + static func %(lhs: BigInt, rhs: BigInt) -> BigInt { + BigInt(lhs.decimal - (lhs.decimal / rhs.decimal).roundToZero * rhs.decimal) + } + static func pow(_ lhs: BigInt, _ rhs: Int) -> BigInt { + BigInt(Foundation.pow(lhs.decimal, rhs)) + } + static prefix func -(_ value: BigInt) -> BigInt { + value * -1 + } + var description: String { + decimal.description + } +} +private extension Decimal { + var roundToZero: Decimal { + let handler: NSDecimalNumberHandler + if self < 0 { + handler = NSDecimalNumberHandler(roundingMode: .up, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) + } else { + handler = NSDecimalNumberHandler(roundingMode: .down, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) + } + return ((self as NSDecimalNumber).rounding(accordingToBehavior: handler) as Decimal) + } +} diff --git a/Tests/AtCoderSupportTests/BigIntTests.swift b/Tests/AtCoderSupportTests/BigIntTests.swift new file mode 100644 index 0000000..622237c --- /dev/null +++ b/Tests/AtCoderSupportTests/BigIntTests.swift @@ -0,0 +1,118 @@ +import XCTest +@testable import AtCoderSupport + +final class BigIntTests: XCTestCase { + func testInitWithString() { + do { + let a: BigInt? = BigInt("1267650600228229401496703205376") + XCTAssertEqual(a, .pow(2, 100)) + } + do { + let a: BigInt? = BigInt("-1267650600228229401496703205376") + XCTAssertEqual(a, -.pow(2, 100)) + } + do { + let a: BigInt? = BigInt("0") + XCTAssertEqual(a, 0) + } + do { + let a: BigInt? = BigInt("ABC") + XCTAssertNil(a) + } + } + + func testDescription() { + do { + let a: BigInt = 42 + XCTAssertEqual(a.description, "42") + } + do { + let a: BigInt = -1 + XCTAssertEqual(a.description, "-1") + } + do { + let a: BigInt = .init(Int.max) + 1 + XCTAssertEqual(a.description, "9223372036854775808") + } + } + + func testPlus() { + do { + let a: BigInt = 2 + let b: BigInt = 3 + XCTAssertEqual(a + b, 5) + } + } + + func testMinus() { + do { + let a: BigInt = 2 + let b: BigInt = 3 + XCTAssertEqual(a - b, -1) + } + } + + func testTimes() { + do { + let a: BigInt = 2 + let b: BigInt = 3 + XCTAssertEqual(a * b, 6) + } + } + + func testDivide() { + do { + let a: BigInt = 7 + let b: BigInt = 3 + XCTAssertEqual(a / b, 2) + } + do { + let a: BigInt = -7 + let b: BigInt = 3 + XCTAssertEqual(a / b, -2) + } + } + + func testReminder() { + do { + let a: BigInt = 6 + let b: BigInt = 3 + XCTAssertEqual(a % b, 0) + } + do { + let a: BigInt = 7 + let b: BigInt = 3 + XCTAssertEqual(a % b, 1) + } + do { + let a: BigInt = 8 + let b: BigInt = 3 + XCTAssertEqual(a % b, 2) + } + do { + let a: BigInt = -6 + let b: BigInt = 3 + XCTAssertEqual(a % b, 0) + } + do { + let a: BigInt = -7 + let b: BigInt = 3 + XCTAssertEqual(a % b, -1) + } + do { + let a: BigInt = -8 + let b: BigInt = 3 + XCTAssertEqual(a % b, -2) + } + } + + func testPow() { + do { + let a: BigInt = 2 + let b: Int = 100 + let r: BigInt = .pow(a, b) + XCTAssertEqual(r, (1 ... 100).reduce(1 as BigInt) { r, _ in r * 2 }) + XCTAssertEqual(r.description, "1267650600228229401496703205376") + } + } +} From cc1b913d3cca1a0a9fbbf4f0736f0bf0d156a7a0 Mon Sep 17 00:00:00 2001 From: Yuta Koshizawa Date: Thu, 10 Dec 2020 05:14:24 +0900 Subject: [PATCH 2/5] Implement `BigInt.init` for `StringProtocol` --- Sources/AtCoderSupport/BigInt.swift | 3 +++ Tests/AtCoderSupportTests/BigIntTests.swift | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Sources/AtCoderSupport/BigInt.swift b/Sources/AtCoderSupport/BigInt.swift index 2a4d522..e71514a 100644 --- a/Sources/AtCoderSupport/BigInt.swift +++ b/Sources/AtCoderSupport/BigInt.swift @@ -11,6 +11,9 @@ struct BigInt: AdditiveArithmetic, ExpressibleByIntegerLiteral, CustomStringConv guard let decimal = Decimal(string: string, locale: Locale(identifier: "en")) else { return nil } self.init(decimal) } + init?(_ string: S) where S: StringProtocol { + self.init(String(string)) + } init(integerLiteral value: Int) { self.init(value) } diff --git a/Tests/AtCoderSupportTests/BigIntTests.swift b/Tests/AtCoderSupportTests/BigIntTests.swift index 622237c..b8ac8f6 100644 --- a/Tests/AtCoderSupportTests/BigIntTests.swift +++ b/Tests/AtCoderSupportTests/BigIntTests.swift @@ -21,6 +21,25 @@ final class BigIntTests: XCTestCase { } } + func testInitWithStringProtocol() { + do { + let a: BigInt? = BigInt("X1267650600228229401496703205376".dropFirst()) + XCTAssertEqual(a, .pow(2, 100)) + } + do { + let a: BigInt? = BigInt("X-1267650600228229401496703205376".dropFirst()) + XCTAssertEqual(a, -.pow(2, 100)) + } + do { + let a: BigInt? = BigInt("X0".dropFirst()) + XCTAssertEqual(a, 0) + } + do { + let a: BigInt? = BigInt("XABC".dropFirst()) + XCTAssertNil(a) + } + } + func testDescription() { do { let a: BigInt = 42 From f0846dcf59b28f79239e5a1922f51a93a4facd0b Mon Sep 17 00:00:00 2001 From: Yuta Koshizawa Date: Thu, 10 Dec 2020 05:27:46 +0900 Subject: [PATCH 3/5] Add test cases for `BigInt` with large number of digits --- Tests/AtCoderSupportTests/BigIntTests.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Tests/AtCoderSupportTests/BigIntTests.swift b/Tests/AtCoderSupportTests/BigIntTests.swift index b8ac8f6..abed16a 100644 --- a/Tests/AtCoderSupportTests/BigIntTests.swift +++ b/Tests/AtCoderSupportTests/BigIntTests.swift @@ -123,6 +123,11 @@ final class BigIntTests: XCTestCase { let b: BigInt = 3 XCTAssertEqual(a % b, -2) } + do { + let a: BigInt = BigInt("1858445835049782285757026664950217712384527500000000")! + let b: BigInt = 998244353 + XCTAssertEqual(a % b, 951633476) + } } func testPow() { @@ -133,5 +138,18 @@ final class BigIntTests: XCTestCase { XCTAssertEqual(r, (1 ... 100).reduce(1 as BigInt) { r, _ in r * 2 }) XCTAssertEqual(r.description, "1267650600228229401496703205376") } + do { + let a: BigInt = 2 + let b: Int = 100 + let r: BigInt = .pow(a, b) + XCTAssertEqual(r, (1 ... 100).reduce(1 as BigInt) { r, _ in r * 2 }) + XCTAssertEqual(r.description, "1267650600228229401496703205376") + } + do { + let a: BigInt = 2 + let b: Int = 512 + let r: BigInt = .pow(a, b) + XCTAssertEqual(r.description, "13​407​807​929​942​597​099​574​024​998​205​846​127​479​365​820​592​393​377​723​561​443​721​764​030​073​546​976​801​874​298​166​903​427​690​031​858​186​486​050​853​753​882​811​946​569​946​433​649​006​084​096") + } } } From 66464472f5c8ead670d8e667b6d1473d873f71f9 Mon Sep 17 00:00:00 2001 From: Yuta Koshizawa Date: Thu, 10 Dec 2020 05:27:46 +0900 Subject: [PATCH 4/5] Remove `Decimal` from `BigInt` --- Sources/AtCoderSupport/BigInt.swift | 238 +++++++++++++++++++++++++--- 1 file changed, 212 insertions(+), 26 deletions(-) diff --git a/Sources/AtCoderSupport/BigInt.swift b/Sources/AtCoderSupport/BigInt.swift index e71514a..691b546 100644 --- a/Sources/AtCoderSupport/BigInt.swift +++ b/Sources/AtCoderSupport/BigInt.swift @@ -1,15 +1,169 @@ import Foundation -struct BigInt: AdditiveArithmetic, ExpressibleByIntegerLiteral, CustomStringConvertible { - private var decimal: Decimal - private init(_ decimal: Decimal) { - self.decimal = decimal +struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLiteral, CustomStringConvertible { + typealias Magnitude = BigUInt + typealias IntegerLiteralType = UInt + + private var words: [UInt] + fileprivate init(words: [UInt]) { + self.words = words } + init?(_ string: String) { + self.init(string[...]) + } + init?(_ string: Substring) { + if string.isEmpty { return nil } + if string == "0" { + self = .zero + return + } + let digitsString: Substring = string + self.init(words: [1]) + let zero: UInt32 = UnicodeScalar("0").value + for c in digitsString.unicodeScalars { + let digit = UInt(c.value - zero) + self *= BigUInt(words: [digit]) + } + } + init(integerLiteral value: UInt) { + self.words = [value] + } + static var zero: BigUInt { .init(words: []) } + static func <(lhs: Self, rhs: Self) -> Bool { + if lhs.words.count < rhs.words.count { + return true + } else if lhs.words.count > rhs.words.count { + return false + } + for (l, r) in zip(lhs.words.reversed(), rhs.words.reversed()) { + if l < r { + return true + } else if l > r { + return false + } + } + return false + } + static func +(lhs: Self, rhs: Self) -> Self { + func plus(l: BigUInt, r: BigUInt) -> BigUInt { + assert(lhs.words.count >= rhs.words.count) + var words: [UInt] = [] + var carry: UInt = 0 + for (lWord, rWord) in zip(l.words, r.words) { + let word = lWord &+ rWord &+ carry + words.append(word) + carry = word > lWord ? 0 : word == lWord ? carry : 1 + } + for lWord in l.words[r.words.count...] { + let word = lWord &+ carry + words.append(word) + carry = word > lWord ? 0 : 1 + } + if carry > 0 { + words.append(carry) + } + return BigUInt(words: words) + } + if lhs.words.count < rhs.words.count { + return plus(l: rhs, r: lhs) + } else { + return plus(l: lhs, r: rhs) + } + } + static func +=(lhs: inout Self, rhs: Self) { + lhs = lhs + rhs + } + static func -(lhs: Self, rhs: Self) -> Self { + precondition(lhs.words.count >= rhs.words.count) + var words: [UInt] = [] + var borrow: UInt = 0 + for (lWord, rWord) in zip(lhs.words, rhs.words) { + let word = lWord &- rWord &- borrow + words.append(word) + borrow = word < lWord ? 0 : word == lWord ? borrow : 1 + } + for lWord in lhs.words[rhs.words.count...] { + let word = lWord &- borrow + words.append(word) + borrow = word < lWord ? 0 : 1 + } + precondition(borrow == 0) + return BigUInt(words: words) + } + static func -=(lhs: inout Self, rhs: Self) { + lhs = lhs - rhs + } + static func *(lhs: Self, rhs: Self) -> Self { + fatalError() + } + static func *=(lhs: inout Self, rhs: Self) { + lhs = lhs * rhs + } + static func /(lhs: Self, rhs: Self) -> Self { + fatalError() + } + static func /=(lhs: inout Self, rhs: Self) { + lhs = lhs / rhs + } + static func %(lhs: Self, rhs: Self) -> Self { + lhs - lhs / rhs * rhs + } + static func %=(lhs: inout Self, rhs: Self) { + lhs = lhs % rhs + } + var description: String { + if self == 0 { return "0" } + + var value: BigUInt = self + var result = "" + while value > 0 { + let digit = value % 10 + assert(digit.words.count == 1) + result.append(digit.words[0].description) + value /= 10 + } + return result + } +} +struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLiteral, CustomStringConvertible { + private enum Sign: Equatable { + case plus + case minus + var flipped: Self { + switch self { + case .plus: return .minus + case .minus: return .plus + } + } + } + private var sign: Sign + private var words: BigUInt + private init(sign: Sign, words: BigUInt) { + self.sign = sign + self.words = words + } + static var zero: BigInt { .init(sign: .plus, words: .zero) } init(_ value: Int) { - decimal = .init(value) + if value > 0 { + self.init(sign: .plus, words: BigUInt(words: [UInt(value)])) + } else if value < 0 { + self.init(sign: .minus, words: BigUInt(words: [UInt(-value)])) + } else { + self = .zero + } } init?(_ string: String) { - guard let decimal = Decimal(string: string, locale: Locale(identifier: "en")) else { return nil } - self.init(decimal) + guard let first = string.first else { return nil } + let sign: Sign + let digitsString: Substring + if first == "-" { + sign = .minus + digitsString = string.dropFirst() + } else { + sign = .plus + digitsString = string[...] + } + guard let words = BigUInt(digitsString) else { return nil } + self.init(sign: sign, words: words) } init?(_ string: S) where S: StringProtocol { self.init(String(string)) @@ -17,39 +171,71 @@ struct BigInt: AdditiveArithmetic, ExpressibleByIntegerLiteral, CustomStringConv init(integerLiteral value: Int) { self.init(value) } + static func <(lhs: BigInt, rhs: BigInt) -> Bool { + switch (lhs.sign, rhs.sign) { + case (.plus, .plus): return lhs.words < rhs.words + case (.plus, .minus): return false + case (.minus, .plus): return true + case (.minus, .minus): return lhs.words > rhs.words + } + } static func +(lhs: BigInt, rhs: BigInt) -> BigInt { - BigInt(lhs.decimal + rhs.decimal) + switch (lhs.sign, rhs.sign) { + case (.plus, .plus): + return BigInt(sign: .plus, words: lhs.words + rhs.words) + case (.plus, .minus): + if lhs.words < rhs.words { + return BigInt(sign: .minus, words: rhs.words - lhs.words) + } else { + return BigInt(sign: .plus, words: lhs.words - rhs.words) + } + case (.minus, .plus): + if lhs.words < rhs.words { + return BigInt(sign: .plus, words: rhs.words - lhs.words) + } else { + return BigInt(sign: .minus, words: lhs.words - rhs.words) + } + case (.minus, .minus): return BigInt(sign: .minus, words: lhs.words + rhs.words) + } + } + static func +=(lhs: inout BigInt, rhs: BigInt) { + lhs = lhs + rhs } static func -(lhs: BigInt, rhs: BigInt) -> BigInt { - BigInt(lhs.decimal - rhs.decimal) + lhs + BigInt(sign: rhs.sign.flipped, words: rhs.words) + } + static func -=(lhs: inout BigInt, rhs: BigInt) { + lhs = lhs - rhs } static func *(lhs: BigInt, rhs: BigInt) -> BigInt { - BigInt(lhs.decimal * rhs.decimal) + let sign: Sign = lhs.sign == rhs.sign ? .plus : .minus + let words = lhs.words * rhs.words + return BigInt(sign: sign, words: words) + } + static func *=(lhs: inout BigInt, rhs: BigInt) { + lhs = lhs * rhs } static func /(lhs: BigInt, rhs: BigInt) -> BigInt { - BigInt((lhs.decimal / rhs.decimal).roundToZero) + let sign: Sign = lhs.sign == rhs.sign ? .plus : .minus + let words = lhs.words / rhs.words + return BigInt(sign: sign, words: words) + } + static func /=(lhs: inout BigInt, rhs: BigInt) { + lhs = lhs / rhs } static func %(lhs: BigInt, rhs: BigInt) -> BigInt { - BigInt(lhs.decimal - (lhs.decimal / rhs.decimal).roundToZero * rhs.decimal) + lhs - lhs / rhs * rhs } - static func pow(_ lhs: BigInt, _ rhs: Int) -> BigInt { - BigInt(Foundation.pow(lhs.decimal, rhs)) + static func %=(lhs: inout BigInt, rhs: BigInt) { + lhs = lhs % rhs + } + static func pow(_ lhs: BigInt, _ rhs: BigInt) -> BigInt { + fatalError() } static prefix func -(_ value: BigInt) -> BigInt { value * -1 } var description: String { - decimal.description - } -} -private extension Decimal { - var roundToZero: Decimal { - let handler: NSDecimalNumberHandler - if self < 0 { - handler = NSDecimalNumberHandler(roundingMode: .up, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) - } else { - handler = NSDecimalNumberHandler(roundingMode: .down, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false) - } - return ((self as NSDecimalNumber).rounding(accordingToBehavior: handler) as Decimal) + sign == .minus ? "-" + words.description : words.description } } From ae05e7a4a105bee60e5ff605283db56acfd8602d Mon Sep 17 00:00:00 2001 From: Yuta Koshizawa Date: Sun, 13 Dec 2020 20:58:24 +0900 Subject: [PATCH 5/5] [WIP] Implement `BigUInt` and `BigInt` without `Decimal` --- Sources/AtCoderSupport/BigInt.swift | 256 +++++++++++++--- Tests/AtCoderSupportTests/BigIntTests.swift | 164 +++++++++-- Tests/AtCoderSupportTests/BigUIntTests.swift | 292 +++++++++++++++++++ 3 files changed, 652 insertions(+), 60 deletions(-) create mode 100644 Tests/AtCoderSupportTests/BigUIntTests.swift diff --git a/Sources/AtCoderSupport/BigInt.swift b/Sources/AtCoderSupport/BigInt.swift index 691b546..13cfb68 100644 --- a/Sources/AtCoderSupport/BigInt.swift +++ b/Sources/AtCoderSupport/BigInt.swift @@ -17,15 +17,20 @@ struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerL return } let digitsString: Substring = string - self.init(words: [1]) + self = 0 let zero: UInt32 = UnicodeScalar("0").value for c in digitsString.unicodeScalars { let digit = UInt(c.value - zero) - self *= BigUInt(words: [digit]) + guard (0 ... 9).contains(digit) else { return nil } + self *= 10 + self += BigUInt(words: [digit]) } } init(integerLiteral value: UInt) { - self.words = [value] + self.init(value) + } + init(_ value: UInt) { + self.init(words: value == 0 ? [] : [value]) } static var zero: BigUInt { .init(words: []) } static func <(lhs: Self, rhs: Self) -> Bool { @@ -44,19 +49,20 @@ struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerL return false } static func +(lhs: Self, rhs: Self) -> Self { - func plus(l: BigUInt, r: BigUInt) -> BigUInt { + func plus(_ lhs: BigUInt, _ rhs: BigUInt) -> BigUInt { assert(lhs.words.count >= rhs.words.count) var words: [UInt] = [] var carry: UInt = 0 - for (lWord, rWord) in zip(l.words, r.words) { - let word = lWord &+ rWord &+ carry + for (lWord, rWord) in zip(lhs.words, rhs.words) { + let (word1, overflow1) = lWord.addingReportingOverflow(rWord) + let (word, overflow2) = word1.addingReportingOverflow(carry) words.append(word) - carry = word > lWord ? 0 : word == lWord ? carry : 1 + carry = overflow1 || overflow2 ? 1 : 0 } - for lWord in l.words[r.words.count...] { - let word = lWord &+ carry + for lWord in lhs.words[rhs.words.count...] { + let (word, overflow) = lWord.addingReportingOverflow(carry) words.append(word) - carry = word > lWord ? 0 : 1 + carry = overflow ? 1 : 0 } if carry > 0 { words.append(carry) @@ -64,9 +70,9 @@ struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerL return BigUInt(words: words) } if lhs.words.count < rhs.words.count { - return plus(l: rhs, r: lhs) + return plus(rhs, lhs) } else { - return plus(l: lhs, r: rhs) + return plus(lhs, rhs) } } static func +=(lhs: inout Self, rhs: Self) { @@ -77,14 +83,18 @@ struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerL var words: [UInt] = [] var borrow: UInt = 0 for (lWord, rWord) in zip(lhs.words, rhs.words) { - let word = lWord &- rWord &- borrow + let (word1, overflow1) = lWord.subtractingReportingOverflow(rWord) + let (word, overflow2) = word1.subtractingReportingOverflow(borrow) words.append(word) - borrow = word < lWord ? 0 : word == lWord ? borrow : 1 + borrow = overflow1 || overflow2 ? 1 : 0 } for lWord in lhs.words[rhs.words.count...] { - let word = lWord &- borrow + let (word, overflow) = lWord.subtractingReportingOverflow(borrow) words.append(word) - borrow = word < lWord ? 0 : 1 + borrow = overflow ? 1 : 0 + } + if let lastWord = words.last, lastWord == 0 { + words.removeLast() } precondition(borrow == 0) return BigUInt(words: words) @@ -92,40 +102,162 @@ struct BigUInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerL static func -=(lhs: inout Self, rhs: Self) { lhs = lhs - rhs } + private static func times(_ lhs: Self, _ rhs: UInt, offset: Int) -> Self { + var words: [UInt] = .init(repeating: 0, count: offset) + var carry: UInt = 0 + for lWord in lhs.words { + let (high, low) = lWord.multipliedFullWidth(by: rhs) + let (word, overflow) = low.addingReportingOverflow(carry) + words.append(word) + carry = high + (overflow ? 1 : 0) + } + if carry > 0 { + words.append(carry) + } + return BigUInt(words: words) + } static func *(lhs: Self, rhs: Self) -> Self { - fatalError() + var result: BigUInt = 0 + for (i, rWord) in rhs.words.enumerated() { + result += times(lhs, rWord, offset: i) + } + return result } static func *=(lhs: inout Self, rhs: Self) { lhs = lhs * rhs } - static func /(lhs: Self, rhs: Self) -> Self { - fatalError() +// static func /(lhs: Self, rhs: Self) -> Self { +// fatalError("Unimplemented yet.") +// } +// static func /=(lhs: inout Self, rhs: Self) { +// lhs = lhs / rhs +// } +// static func %(lhs: Self, rhs: Self) -> Self { +// lhs - lhs / rhs * rhs +// } +// static func %=(lhs: inout Self, rhs: Self) { +// lhs = lhs % rhs +// } + func quotientAndRemainder(dividingBy rhs: UInt) -> (quotient: BigUInt, remainder: UInt) { + var quotientWords: [UInt] = [] + var remainder: UInt = 0 + for word in self.words.reversed() { + let quotient: UInt + (quotient, remainder) = rhs.dividingFullWidth((high: remainder, low: word)) + if quotientWords.isEmpty, quotient == 0 { continue } + quotientWords.append(quotient) + } + return (quotient: BigUInt(words: quotientWords.reversed()), remainder: remainder) + } + static func /(lhs: Self, rhs: UInt) -> Self { + let (quotient, _) = lhs.quotientAndRemainder(dividingBy: rhs) + return quotient } - static func /=(lhs: inout Self, rhs: Self) { + static func /=(lhs: inout Self, rhs: UInt) { lhs = lhs / rhs } - static func %(lhs: Self, rhs: Self) -> Self { - lhs - lhs / rhs * rhs + static func %(lhs: Self, rhs: UInt) -> UInt { + let (_, remainder) = lhs.quotientAndRemainder(dividingBy: rhs) + return remainder } - static func %=(lhs: inout Self, rhs: Self) { - lhs = lhs % rhs + static func %=(lhs: inout Self, rhs: UInt) { + lhs = BigUInt(lhs % rhs) + } + static func &(lhs: Self, rhs: Self) -> Self { + var long: [UInt] + let short: [UInt] + if lhs.words.count < rhs.words.count { + short = lhs.words + long = rhs.words + } else { + short = rhs.words + long = lhs.words + } + for (i, word) in short.enumerated() { + long[i] &= word + } + return BigUInt(words: long) + } + static func |(lhs: Self, rhs: Self) -> Self { + var long: [UInt] + let short: [UInt] + if lhs.words.count < rhs.words.count { + short = lhs.words + long = rhs.words + } else { + short = rhs.words + long = lhs.words + } + for (i, word) in short.enumerated() { + long[i] |= word + } + return BigUInt(words: long) + } + static func <<(lhs: Self, rhs: Int) -> Self { + if rhs < 0 { return lhs >> -rhs } +// let (wordShift, digitShift) = rhs.quotientAndRemainder(dividingBy: MemoryLayout.size) + fatalError() + } + static func <<=(lhs: inout Self, rhs: Int) { + lhs = lhs << rhs + } + static func >>(lhs: Self, rhs: Int) -> Self { + if rhs < 0 { return lhs << -rhs } + let (wordShift, bitShift) = rhs.quotientAndRemainder(dividingBy: MemoryLayout.size * 8) + if wordShift >= lhs.words.count { return 0 } + var words: [UInt] = [] + let maskBitShift = MemoryLayout.size * 8 - bitShift + let mask = UInt.max >> maskBitShift + var low: UInt? + for high in lhs.words[wordShift...] { + if let low = low { + let word = (low >> bitShift) | ((high & mask) << maskBitShift) + words.append(word) + } + low = high + } + if let low = low { + let word = low >> bitShift + if word != 0 { + words.append(word) + } + } + return BigUInt(words: words) + } + static func >>=(lhs: inout Self, rhs: Int) { + lhs = lhs >> rhs + } + static func pow(_ lhs: BigUInt, _ rhs: UInt) -> BigUInt { + var result: BigUInt = 1 + var a = lhs + var b = rhs + while true { + if b & 0x1 != 0 { + result *= a + } + b >>= 1 + guard b > 0 else { break } + a *= a + } + return result } var description: String { - if self == 0 { return "0" } + if words.isEmpty { return "0" } + if words.count == 1 { return words[0].description } var value: BigUInt = self var result = "" while value > 0 { - let digit = value % 10 + let digit: UInt + (value, digit) = value.quotientAndRemainder(dividingBy: 10) assert(digit.words.count == 1) result.append(digit.words[0].description) - value /= 10 } - return result + return String(result.reversed()) } } struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLiteral, CustomStringConvertible { - private enum Sign: Equatable { + fileprivate enum Sign: Equatable { case plus case minus var flipped: Self { @@ -134,6 +266,12 @@ struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLi case .minus: return .plus } } + var coefficient: Int { + switch self { + case .plus: return 1 + case .minus: return -1 + } + } } private var sign: Sign private var words: BigUInt @@ -163,7 +301,12 @@ struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLi digitsString = string[...] } guard let words = BigUInt(digitsString) else { return nil } - self.init(sign: sign, words: words) + if sign == .minus, words == 0 { + self.init(sign: .plus, words:words ) + } + else { + self.init(sign: sign, words: words) + } } init?(_ string: S) where S: StringProtocol { self.init(String(string)) @@ -215,22 +358,46 @@ struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLi static func *=(lhs: inout BigInt, rhs: BigInt) { lhs = lhs * rhs } - static func /(lhs: BigInt, rhs: BigInt) -> BigInt { - let sign: Sign = lhs.sign == rhs.sign ? .plus : .minus - let words = lhs.words / rhs.words - return BigInt(sign: sign, words: words) - } - static func /=(lhs: inout BigInt, rhs: BigInt) { +// static func /(lhs: BigInt, rhs: BigInt) -> BigInt { +// let sign: Sign = lhs.sign == rhs.sign ? .plus : .minus +// let words = lhs.words / rhs.words +// return BigInt(sign: sign, words: words) +// } +// static func /=(lhs: inout BigInt, rhs: BigInt) { +// lhs = lhs / rhs +// } +// static func %(lhs: BigInt, rhs: BigInt) -> BigInt { +// lhs - lhs / rhs * rhs +// } +// static func %=(lhs: inout BigInt, rhs: BigInt) { +// lhs = lhs % rhs +// } + func quotientAndRemainder(dividingBy rhs: Int) -> (quotient: BigInt, remainder: Int) { + let (quotientWords, remainderWords) = words.quotientAndRemainder(dividingBy: UInt(abs(rhs))) + return (quotient: BigInt(sign: sign, words: quotientWords), remainder: Int(remainderWords) * sign.coefficient) + } + static func /(lhs: BigInt, rhs: Int) -> BigInt { + let (quotient, _) = lhs.quotientAndRemainder(dividingBy: rhs) + return quotient + } + static func /=(lhs: inout BigInt, rhs: Int) { lhs = lhs / rhs } - static func %(lhs: BigInt, rhs: BigInt) -> BigInt { - lhs - lhs / rhs * rhs + static func %(lhs: BigInt, rhs: Int) -> Int { + let (_, remainder) = lhs.quotientAndRemainder(dividingBy: rhs) + return remainder } - static func %=(lhs: inout BigInt, rhs: BigInt) { - lhs = lhs % rhs + static func %=(lhs: inout BigInt, rhs: Int) { + lhs = BigInt(lhs % rhs) } - static func pow(_ lhs: BigInt, _ rhs: BigInt) -> BigInt { - fatalError() + static func pow(_ lhs: BigInt, _ rhs: Int) -> BigInt { + precondition(rhs >= 0) + let sign: Sign + switch lhs.sign { + case .minus: sign = rhs.isMultiple(of: 2) ? .plus : .minus + case .plus: sign = .plus + } + return BigInt(sign: sign, words: .pow(lhs.words, UInt(rhs))) } static prefix func -(_ value: BigInt) -> BigInt { value * -1 @@ -239,3 +406,8 @@ struct BigInt: AdditiveArithmetic, Equatable, Comparable, ExpressibleByIntegerLi sign == .minus ? "-" + words.description : words.description } } +private extension Collection { + func _BigInt_pairs() -> Zip2Sequence { + return zip(self, dropFirst()) + } +} diff --git a/Tests/AtCoderSupportTests/BigIntTests.swift b/Tests/AtCoderSupportTests/BigIntTests.swift index abed16a..d879b8b 100644 --- a/Tests/AtCoderSupportTests/BigIntTests.swift +++ b/Tests/AtCoderSupportTests/BigIntTests.swift @@ -6,15 +6,25 @@ final class BigIntTests: XCTestCase { do { let a: BigInt? = BigInt("1267650600228229401496703205376") XCTAssertEqual(a, .pow(2, 100)) + XCTAssertEqual(a?.description, "1267650600228229401496703205376") } do { let a: BigInt? = BigInt("-1267650600228229401496703205376") XCTAssertEqual(a, -.pow(2, 100)) + XCTAssertEqual(a?.description, "-1267650600228229401496703205376") + } + do { + let a: BigInt? = BigInt("36893488147419103230") + XCTAssertEqual(a?.description, "36893488147419103230") } do { let a: BigInt? = BigInt("0") XCTAssertEqual(a, 0) } + do { + let a: BigInt? = BigInt("-0") + XCTAssertEqual(a, 0) + } do { let a: BigInt? = BigInt("ABC") XCTAssertNil(a) @@ -25,15 +35,25 @@ final class BigIntTests: XCTestCase { do { let a: BigInt? = BigInt("X1267650600228229401496703205376".dropFirst()) XCTAssertEqual(a, .pow(2, 100)) + XCTAssertEqual(a?.description, "1267650600228229401496703205376") } do { let a: BigInt? = BigInt("X-1267650600228229401496703205376".dropFirst()) XCTAssertEqual(a, -.pow(2, 100)) + XCTAssertEqual(a?.description, "-1267650600228229401496703205376") + } + do { + let a: BigInt? = BigInt("X36893488147419103230".dropFirst()) + XCTAssertEqual(a?.description, "36893488147419103230") } do { let a: BigInt? = BigInt("X0".dropFirst()) XCTAssertEqual(a, 0) } + do { + let a: BigInt? = BigInt("X-0".dropFirst()) + XCTAssertEqual(a, 0) + } do { let a: BigInt? = BigInt("XABC".dropFirst()) XCTAssertNil(a) @@ -53,6 +73,20 @@ final class BigIntTests: XCTestCase { let a: BigInt = .init(Int.max) + 1 XCTAssertEqual(a.description, "9223372036854775808") } + do { + if MemoryLayout.size == 8 { + let a: BigUInt = .init(UInt.max) + 1 + XCTAssertEqual(a.description, "18446744073709551616") + } + } + do { + let a: BigInt = .pow(2, 512) + XCTAssertEqual(a.description, "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096") + } + do { + let a: BigInt = .pow(-2, 513) + XCTAssertEqual(a.description, "-26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192") + } } func testPlus() { @@ -61,6 +95,50 @@ final class BigIntTests: XCTestCase { let b: BigInt = 3 XCTAssertEqual(a + b, 5) } + do { + let a: BigInt = 2 + let b: BigInt = -3 + XCTAssertEqual(a + b, -1) + } + do { + let a: BigInt = -2 + let b: BigInt = 3 + XCTAssertEqual(a + b, 1) + } + do { + let a: BigInt = -2 + let b: BigInt = -3 + XCTAssertEqual(a + b, -5) + } + do { + let a: BigInt = 3 + let b: BigInt = 2 + XCTAssertEqual(a + b, 5) + } + do { + let a: BigInt = 3 + let b: BigInt = -2 + XCTAssertEqual(a + b, 1) + } + do { + let a: BigInt = -3 + let b: BigInt = 2 + XCTAssertEqual(a + b, -1) + } + do { + let a: BigInt = -3 + let b: BigInt = -2 + XCTAssertEqual(a + b, -5) + } + do { + if MemoryLayout.size == 8 { + let a: BigInt = .init(Int.max) + XCTAssertEqual(a + a, BigInt("18446744073709551614")) + XCTAssertEqual(a + a + a, BigInt("27670116110564327421")) + XCTAssertEqual(a + a + a + a, BigInt("36893488147419103228")) + XCTAssertEqual(a + a + a + a + a, BigInt("46116860184273879035")) + } + } } func testMinus() { @@ -69,6 +147,41 @@ final class BigIntTests: XCTestCase { let b: BigInt = 3 XCTAssertEqual(a - b, -1) } + do { + let a: BigInt = 2 + let b: BigInt = -3 + XCTAssertEqual(a - b, 5) + } + do { + let a: BigInt = -2 + let b: BigInt = 3 + XCTAssertEqual(a - b, -5) + } + do { + let a: BigInt = -2 + let b: BigInt = -3 + XCTAssertEqual(a - b, 1) + } + do { + let a: BigInt = 3 + let b: BigInt = 2 + XCTAssertEqual(a - b, 1) + } + do { + let a: BigInt = 3 + let b: BigInt = -2 + XCTAssertEqual(a - b, 5) + } + do { + let a: BigInt = -3 + let b: BigInt = 2 + XCTAssertEqual(a - b, -5) + } + do { + let a: BigInt = -3 + let b: BigInt = -2 + XCTAssertEqual(a - b, -1) + } } func testTimes() { @@ -82,52 +195,74 @@ final class BigIntTests: XCTestCase { func testDivide() { do { let a: BigInt = 7 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a / b, 2) } do { let a: BigInt = -7 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a / b, -2) } } - func testReminder() { + func testRemainder() { do { let a: BigInt = 6 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, 0) } do { let a: BigInt = 7 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, 1) } do { let a: BigInt = 8 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, 2) } do { let a: BigInt = -6 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, 0) } do { let a: BigInt = -7 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, -1) } do { let a: BigInt = -8 - let b: BigInt = 3 + let b: Int = 3 XCTAssertEqual(a % b, -2) } do { let a: BigInt = BigInt("1858445835049782285757026664950217712384527500000000")! - let b: BigInt = 998244353 + let b: Int = 998244353 XCTAssertEqual(a % b, 951633476) } + do { // sign + do { + let a: BigInt = 11 + let b: Int = 3 + XCTAssertEqual(a % b, 11 % 3) + } + do { + let a: BigInt = -11 + let b: Int = 3 + XCTAssertEqual(a % b, -11 % 3) + } + do { + let a: BigInt = 11 + let b: Int = -3 + XCTAssertEqual(a % b, 11 % -3) + } + do { + let a: BigInt = -11 + let b: Int = -3 + XCTAssertEqual(a % b, -11 % -3) + } + } } func testPow() { @@ -138,18 +273,11 @@ final class BigIntTests: XCTestCase { XCTAssertEqual(r, (1 ... 100).reduce(1 as BigInt) { r, _ in r * 2 }) XCTAssertEqual(r.description, "1267650600228229401496703205376") } - do { - let a: BigInt = 2 - let b: Int = 100 - let r: BigInt = .pow(a, b) - XCTAssertEqual(r, (1 ... 100).reduce(1 as BigInt) { r, _ in r * 2 }) - XCTAssertEqual(r.description, "1267650600228229401496703205376") - } do { let a: BigInt = 2 let b: Int = 512 let r: BigInt = .pow(a, b) - XCTAssertEqual(r.description, "13​407​807​929​942​597​099​574​024​998​205​846​127​479​365​820​592​393​377​723​561​443​721​764​030​073​546​976​801​874​298​166​903​427​690​031​858​186​486​050​853​753​882​811​946​569​946​433​649​006​084​096") + XCTAssertEqual(r.description, "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096") } } } diff --git a/Tests/AtCoderSupportTests/BigUIntTests.swift b/Tests/AtCoderSupportTests/BigUIntTests.swift new file mode 100644 index 0000000..de188bf --- /dev/null +++ b/Tests/AtCoderSupportTests/BigUIntTests.swift @@ -0,0 +1,292 @@ +import XCTest +@testable import AtCoderSupport + +final class BigUIntTests: XCTestCase { + func testInitWithString() { + do { + let a: BigUInt? = BigUInt("1267650600228229401496703205376") + XCTAssertEqual(a, .pow(2, 100)) + XCTAssertEqual(a?.description, "1267650600228229401496703205376") + } + do { + let a: BigUInt? = BigUInt("36893488147419103230") + XCTAssertEqual(a?.description, "36893488147419103230") + } + do { + let a: BigUInt? = BigUInt("0") + XCTAssertEqual(a, 0) + XCTAssertEqual(a?.description, "0") + } + do { + let a: BigUInt? = BigUInt("ABC") + XCTAssertNil(a) + } + } + + func testInitWithStringProtocol() { + do { + let a: BigUInt? = BigUInt("X1267650600228229401496703205376".dropFirst()) + XCTAssertEqual(a, .pow(2, 100)) + XCTAssertEqual(a?.description, "1267650600228229401496703205376") + } + do { + let a: BigUInt? = BigUInt("X36893488147419103230".dropFirst()) + XCTAssertEqual(a?.description, "36893488147419103230") + } + do { + let a: BigUInt? = BigUInt("X0".dropFirst()) + XCTAssertEqual(a, 0) + XCTAssertEqual(a?.description, "0") + } + do { + let a: BigUInt? = BigUInt("XABC".dropFirst()) + XCTAssertNil(a) + } + } + + func testDescription() { + do { + let a: BigUInt = 42 + XCTAssertEqual(a.description, "42") + } + do { + if MemoryLayout.size == 8 { + let a: BigUInt = .init(UInt.max) + 1 + XCTAssertEqual(a.description, "18446744073709551616") + } + } + do { + let a: BigUInt = .pow(2, 512) + XCTAssertEqual(a.description, "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096") + } + } + + func testLessThan() { + do { + let a: BigUInt = 2 + let b: BigUInt = 3 + XCTAssertTrue(a < b) + } + do { + let a: BigUInt = 3 + let b: BigUInt = 2 + XCTAssertFalse(a < b) + } + do { + let a: BigUInt = 2 + let b: BigUInt = 2 + XCTAssertFalse(a < b) + } + do { + let a: BigUInt = 0 + let b: BigUInt = 1 + XCTAssertTrue(a < b) + } + do { + let a: BigUInt = 1 + let b: BigUInt = 0 + XCTAssertFalse(a < b) + } + do { + let a: BigUInt = 0 + let b: BigUInt = 0 + XCTAssertFalse(a < b) + } + do { + let a: BigUInt = BigUInt(UInt.max) + let b: BigUInt = BigUInt(UInt.max) + 1 + XCTAssertTrue(a < b) + } + do { + let a: BigUInt = BigUInt(UInt.max) + 1 + let b: BigUInt = BigUInt(UInt.max) + XCTAssertFalse(a < b) + } + } + + func testPlus() { + do { + let a: BigUInt = 2 + let b: BigUInt = 3 + XCTAssertEqual(a + b, 5) + } + do { + if MemoryLayout.size == 8 { + let a: BigUInt = .init(UInt.max) + XCTAssertEqual(a + a, BigUInt("36893488147419103230")) + } + } + do { + let a: BigUInt = .pow(2, 512) + let b: BigUInt = .pow(2, 511) + XCTAssertEqual(a + b, BigUInt("20111711894913895649361037497308769191219048730888590066585342165582646045110320465202811447250355141535047787279729076280630824217919854919650473509126144")) + } + do { + let a: BigUInt = .pow(2, 512) + let b: BigUInt = .pow(2, 256) + XCTAssertEqual(a + b, BigUInt("13407807929942597099574024998205846127479365820592393377723561443721764030073662768891111614362326998675040546094339320838419523375986027530441562135724032")) + } + } + + func testMinus() { + do { + let a: BigUInt = 3 + let b: BigUInt = 2 + XCTAssertEqual(a - b, 1) + } + do { + let a: BigUInt = .pow(2, 512) + let b: BigUInt = .pow(2, 511) + XCTAssertEqual(a - b, BigUInt("6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048")) + } + do { + let a: BigUInt = .pow(2, 512) + let b: BigUInt = .pow(2, 256) + XCTAssertEqual(a - b, BigUInt("13407807929942597099574024998205846127479365820592393377723561443721764030073431184712636981971479856705023170278632780869088242247907112362425735876444160")) + } + } + + func testTimes() { + do { + let a: BigUInt = 2 + let b: BigUInt = 3 + XCTAssertEqual(a * b, 6) + } + do { + var a: BigUInt = 1 + for _ in 1 ... 512 { + a *= 2 + } + XCTAssertEqual(a, BigUInt("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096")) + XCTAssertEqual(a.description, "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096") + + } + do { + if MemoryLayout.size == 8 { + let a: BigUInt = BigUInt(UInt.max) + XCTAssertEqual(a * a, BigUInt("340282366920938463426481119284349108225")) + XCTAssertEqual(a * a * a, BigUInt("6277101735386680762814942322444851025767571854389858533375")) + XCTAssertEqual(a * a * a * a, BigUInt("115792089237316195398462578067141184799968521174335529155754622898352762650625")) + } + } + do { + let a: BigUInt = .pow(2, 512) + let b: BigUInt = .pow(3, 128) + XCTAssertEqual(a * b, BigUInt("158080530276890286122762315299176464969805626656606331308148944306682275662269021286526559033136370664500949844684512051241289100907713600649203674734260105986549738626670637536231374508536832139371969829181384032256")) + } + } + + func testDivide() { + do { + let a: BigUInt = 7 + let b: UInt = 3 + XCTAssertEqual(a / b, 2) + } + do { + let a: BigUInt = BigUInt(UInt.max) + BigUInt(UInt.max) + let b: UInt = 2 + XCTAssertEqual(a / b, BigUInt(UInt.max)) + } + do { + let a: BigUInt = BigUInt(UInt.max) + BigUInt(UInt.max) + let b: UInt = .max + XCTAssertEqual(a / b, 2) + } + do { + let a: BigUInt = .pow(2, 512) + let b: UInt = 2 + XCTAssertEqual(a / b, .pow(2, 511)) + } + do { + let a: BigUInt = .pow(2, 512) + let b: UInt = 1 << 31 + XCTAssertEqual(a / b, .pow(2, 481)) + } + do { + let a: BigUInt = .pow(2, 512) + let b: UInt = 123456789 + XCTAssertEqual(a / b, BigUInt("108603245220824568016053171431551213659698907450058444155092689505489763143552575118423615392806817838831300384675370512461278114174398055553134862")) + } + } + + func testRemainder() { + do { + let a: BigUInt = 6 + let b: UInt = 3 + XCTAssertEqual(a % b, 0) + } + do { + let a: BigUInt = 7 + let b: UInt = 3 + XCTAssertEqual(a % b, 1) + } + do { + let a: BigUInt = 8 + let b: UInt = 3 + XCTAssertEqual(a % b, 2) + } + do { + let a: BigUInt = .pow(2, 100) + XCTAssertEqual(a % 2, 0) + XCTAssertEqual(a % 4, 0) + XCTAssertEqual(a % 8, 0) + XCTAssertEqual(a % 16, 0) + XCTAssertEqual(a % 1 << 31, 0) + } + do { + let a: BigUInt = BigUInt(UInt.max) * 10 + 1 + let b: UInt = .max + XCTAssertEqual(a % b, 1) + } + do { + let a: BigUInt = .pow(2, 512) + let b: UInt = 123456789 + XCTAssertEqual(a % b, 59605978) + } + do { + let a: BigUInt = BigUInt("1858445835049782285757026664950217712384527500000000")! + let b: UInt = 998244353 + XCTAssertEqual(a % b, 951633476) + } + } + + func testRightShift() { + do { + let a: BigUInt = 7 + XCTAssertEqual(a >> 1, 3) + } + do { + let a: BigUInt = .pow(3, 128) + XCTAssertEqual(a >> 1, BigUInt("5895092288869291585760436430706259332839105796137920554548480")) + } + do { + let a: BigUInt = .pow(3, 256) + XCTAssertEqual(a >> 100, BigUInt("109658333575606304232296601271443558971917571123765177973041041632575963156099137956140949597")) + } + do { + let a: BigUInt = .pow(3, 256) + XCTAssertEqual(a >> 200, BigUInt("86505172289480461362381148729559697079984195950879243965911039")) + } + do { + let a: BigUInt = .pow(3, 256) + XCTAssertEqual(a >> 1000, 0) + } + } + + func testPow() { + do { + let a: BigUInt = 2 + let b: UInt = 100 + let r: BigUInt = .pow(a, b) + XCTAssertEqual(r, (1 ... 100).reduce(1 as BigUInt) { r, _ in r * 2 }) + XCTAssertEqual(r.description, "1267650600228229401496703205376") + } + do { + let a: BigUInt = 2 + let b: UInt = 512 + let r: BigUInt = .pow(a, b) + XCTAssertEqual(r.description, "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096") + } + } + +}