BigInt for swiftのソースコードを記述します。
まず下記のディレクトリ構造を用意してください。
Documents
|ー swift ソースコード
|_ BigInt
|__ Sources
|_BigInt
|_BigInt.swift
下記のコードをテキストエディタにコピー&ペーストし、ファイル名を BigInt.swift に変更します。拡張子は .swift としてください。下記のソースコードはかなり長いです。次の作業は明日にします。
import Foundation
public struct BigInt: ExpressibleByStringLiteral, ExpressibleByIntegerLiteral, Comparable, CustomStringConvertible {
public var digits: [UInt8]
public var isNegative: Bool
// MARK: - 初期化
public init(digits: [UInt8], isNegative: Bool = false) {
var trimmed = digits
while trimmed.count > 1 && trimmed.last == 0 { trimmed.removeLast() }
self.digits = trimmed
self.isNegative = trimmed == [0] ? false : isNegative
}
public init(_ value: Int) {
var num = value
self.isNegative = num < 0
num = Swift.abs(num)
if num == 0 { self.digits = [0] }
else {
var arr: [UInt8] = []
while num > 0 {
arr.append(UInt8(num % 10))
num /= 10
}
self.digits = arr
}
}
public init(_ number: String) {
var str = number.trimmingCharacters(in: .whitespaces)
if str.hasPrefix("-") { isNegative = true; str.removeFirst() }
else { isNegative = false }
let significant = str.drop(while: { $0 == "0" })
let trimmed = String(significant)
if trimmed.isEmpty { digits = [0]; isNegative = false }
else { digits = trimmed.reversed().compactMap { UInt8(String($0)) } }
}
public init(stringLiteral value: StringLiteralType) { self.init(value) }
public init(integerLiteral value: Int) { self.init(value) }
// MARK: - 表示
public var description: String {
let num = digits.reversed().map { String($0) }.joined()
return (isNegative && num != "0" ? "-" : "") + num
}
// MARK: - 比較
public static func == (lhs: BigInt, rhs: BigInt) -> Bool {
lhs.isNegative == rhs.isNegative && lhs.digits == rhs.digits
}
public static func < (lhs: BigInt, rhs: BigInt) -> Bool {
if lhs.isNegative != rhs.isNegative { return lhs.isNegative }
if lhs.digits.count != rhs.digits.count {
return lhs.isNegative ? lhs.digits.count > rhs.digits.count : lhs.digits.count < rhs.digits.count
}
for (a, b) in zip(lhs.digits.reversed(), rhs.digits.reversed()) {
if a != b { return lhs.isNegative ? a > b : a < b }
}
return false
}
// MARK: - ユーティリティ
public var isEven: Bool { digits.first! % 2 == 0 }
public var isOdd: Bool { !isEven }
public func digitCount() -> Int { digits.count }
public func abs() -> BigInt { BigInt(digits: digits, isNegative: false) }
// MARK: - 演算子
public static func + (lhs: BigInt, rhs: BigInt) -> BigInt {
if lhs.isNegative == rhs.isNegative { return add(lhs, rhs, sign: lhs.isNegative) }
else {
if lhs.abs() >= rhs.abs() { return subtract(lhs, rhs, sign: lhs.isNegative) }
else { return subtract(rhs, lhs, sign: rhs.isNegative) }
}
}
public static func - (lhs: BigInt, rhs: BigInt) -> BigInt { lhs + BigInt(digits: rhs.digits, isNegative: !rhs.isNegative) }
public static func * (lhs: BigInt, rhs: BigInt) -> BigInt {
var result = [UInt8](repeating: 0, count: lhs.digits.count + rhs.digits.count)
for (i, a) in lhs.digits.enumerated() {
var carry = 0
for (j, b) in rhs.digits.enumerated() {
let sum = Int(result[i + j]) + Int(a) * Int(b) + carry
result[i + j] = UInt8(sum % 10)
carry = sum / 10
}
if carry > 0 { result[i + rhs.digits.count] += UInt8(carry) }
}
return BigInt(digits: result, isNegative: lhs.isNegative != rhs.isNegative)
}
public static func / (lhs: BigInt, rhs: BigInt) -> BigInt {
precondition(rhs != BigInt(0), "Division by zero")
if lhs.abs() < rhs.abs() { return BigInt(0) }
var quotient = [UInt8]()
var remainder = BigInt(0)
for digit in lhs.digits.reversed() {
remainder.digits.insert(digit, at: 0)
remainder = BigInt(digits: remainder.digits, isNegative: false)
var count = 0
while remainder >= rhs.abs() {
remainder = remainder - rhs.abs()
count += 1
}
quotient.append(UInt8(count))
}
quotient.reverse()
return BigInt(digits: quotient.reversed(), isNegative: lhs.isNegative != rhs.isNegative)
}
public static func % (lhs: BigInt, rhs: BigInt) -> BigInt { lhs - (lhs / rhs) * rhs }
// MARK: - 複合代入
public static func += (lhs: inout BigInt, rhs: BigInt) { lhs = lhs + rhs }
public static func -= (lhs: inout BigInt, rhs: BigInt) { lhs = lhs - rhs }
public static func *= (lhs: inout BigInt, rhs: BigInt) { lhs = lhs * rhs }
public static func /= (lhs: inout BigInt, rhs: BigInt) { lhs = lhs / rhs }
// MARK: - 単項マイナス
public static prefix func - (value: BigInt) -> BigInt { BigInt(digits: value.digits, isNegative: !value.isNegative) }
// MARK: - 内部加減算
private static func add(_ lhs: BigInt, _ rhs: BigInt, sign: Bool) -> BigInt {
let maxLength = max(lhs.digits.count, rhs.digits.count)
var result = [UInt8]()
var carry = 0
for i in 0..<maxLength {
let sum = (i < lhs.digits.count ? Int(lhs.digits[i]) : 0) + (i < rhs.digits.count ? Int(rhs.digits[i]) : 0) + carry
result.append(UInt8(sum % 10))
carry = sum / 10
}
if carry > 0 { result.append(UInt8(carry)) }
return BigInt(digits: result, isNegative: sign)
}
private static func subtract(_ lhs: BigInt, _ rhs: BigInt, sign: Bool) -> BigInt {
var result = [UInt8](), borrow = 0
for i in 0..<lhs.digits.count {
var diff = Int(lhs.digits[i]) - (i < rhs.digits.count ? Int(rhs.digits[i]) : 0) - borrow
if diff < 0 { diff += 10; borrow = 1 } else { borrow = 0 }
result.append(UInt8(diff))
}
return BigInt(digits: result, isNegative: sign)
}
}
// MARK: - 数学関数
public extension BigInt {
static func pow(_ base: BigInt, _ exp: Int) -> BigInt {
guard exp >= 0 else { fatalError("Negative exponent") }
var result = BigInt(1), baseCopy = base, exponent = exp
while exponent > 0 {
if exponent % 2 == 1 { result *= baseCopy }
baseCopy *= baseCopy
exponent /= 2
}
return result
}
static func modPow(_ base: BigInt, _ exp: BigInt, _ mod: BigInt) -> BigInt {
var result = BigInt(1), baseCopy = base % mod, exponent = exp
while exponent > BigInt(0) {
if exponent.isOdd { result = (result * baseCopy) % mod }
baseCopy = (baseCopy * baseCopy) % mod
exponent /= BigInt(2)
}
return result
}
static func factorial(_ n: Int) -> BigInt {
guard n >= 0 else { fatalError("Negative factorial") }
var result: BigInt = 1
for i in 2...n { result *= BigInt(i) }
return result
}
static func gcd(_ a: BigInt, _ b: BigInt) -> BigInt {
var x = a.abs(), y = b.abs()
while y != BigInt(0) { let t = y; y = x % y; x = t }
return x
}
static func lcm(_ a: BigInt, _ b: BigInt) -> BigInt {
(a.abs() / gcd(a, b)) * b.abs()
}
static func sqrt(of n: BigInt) -> BigInt {
precondition(!n.isNegative, "Negative sqrt")
if n == BigInt(0) || n == BigInt(1) { return n }
var low = BigInt(0), high = n, ans = BigInt(0)
while low <= high {
let mid = (low + high) / BigInt(2), sq = mid * mid
if sq == n { return mid }
else if sq < n { ans = mid; low = mid + BigInt(1) }
else { high = mid - BigInt(1) }
}
return ans
}
static func isPerfectSquare(_ n: BigInt) -> Bool {
let r = sqrt(of: n)
return r * r == n
}
static func isProbablePrime(_ n: BigInt, k: Int = 5) -> Bool {
if n <= BigInt(1) { return false }
if n == BigInt(2) || n == BigInt(3) { return true }
if n.isEven { return false }
var d = n - BigInt(1), r = 0
while d.isEven { d /= BigInt(2); r += 1 }
for _ in 0..<k {
let a = BigInt.random(in: BigInt(2)...(n - BigInt(2)))
var x = modPow(a, d, n)
if x == BigInt(1) || x == n - BigInt(1) { continue }
var cont = false
for _ in 1..<r {
x = modPow(x, 2, n)
if x == n - BigInt(1) { cont = true; break }
}
if !cont { return false }
}
return true
}
}
// MARK: - 乱数
public extension BigInt {
static func random(digits count: Int) -> BigInt {
precondition(count > 0)
var result: [UInt8] = [UInt8(Int.random(in: 1...9))]
for _ in 1..<count { result.append(UInt8(Int.random(in: 0...9))) }
return BigInt(digits: result.reversed())
}
static func random(in range: ClosedRange<BigInt>) -> BigInt {
var diff = range.upperBound - range.lowerBound
var rand = BigInt.random(digits: diff.digitCount())
while rand > diff { rand = BigInt.random(digits: diff.digitCount()) }
return range.lowerBound + rand
}
}
// MARK: - 表示 & 変換
public extension BigInt {
func formatted() -> String {
let str = self.digits.reversed().map(String.init).joined()
var result = "", count = 0
for char in str.reversed() {
if count > 0 && count % 3 == 0 { result.append(",") }
result.append(char); count += 1
}
return String(result.reversed())
}
func toHexString() -> String {
if self == BigInt(0) { return "0" }
let hexChars = Array("0123456789ABCDEF")
var value = self.isNegative ? -self : self
var result = ""
while value > BigInt(0) {
let (q, r) = value.divmod(BigInt(16))
result.append(hexChars[r.toIntSafe()])
value = q
}
return (isNegative ? "-" : "") + String(result.reversed())
}
static func fromHexString(_ hex: String) -> BigInt {
var str = hex.uppercased()
var isNeg = false
if str.hasPrefix("-") { isNeg = true; str.removeFirst() }
var result = BigInt(0)
for char in str {
result *= BigInt(16)
if let val = "0123456789ABCDEF".firstIndex(of: char)?.utf16Offset(in: "0123456789ABCDEF") {
result += BigInt(val)
}
}
return isNeg ? -result : result
}
func toBinaryString() -> String {
if self == BigInt(0) { return "0" }
var value = self.isNegative ? -self : self
var result = ""
while value > BigInt(0) {
let (q, r) = value.divmod(BigInt(2))
result.append(r.toIntSafe() == 1 ? "1" : "0")
value = q
}
return (isNegative ? "-" : "") + String(result.reversed())
}
func toBaseString(_ base: Int) -> String {
precondition((2...36).contains(base), "Base must be 2...36")
let chars = Array("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
if self == BigInt(0) { return "0" }
var value = self.isNegative ? -self : self
var result = ""
while value > BigInt(0) {
let (q, r) = value.divmod(BigInt(base))
result.append(chars[r.toIntSafe()])
value = q
}
return (isNegative ? "-" : "") + String(result.reversed())
}
func divmod(_ divisor: BigInt) -> (BigInt, BigInt) {
precondition(divisor != BigInt(0), "Division by zero")
var quotient = BigInt(0)
var remainder = BigInt(0)
for digit in self.digits.reversed() {
remainder.digits.insert(digit, at: 0)
remainder = BigInt(digits: remainder.digits, isNegative: false)
var count = 0
while remainder >= divisor {
remainder = remainder - divisor
count += 1
}
quotient.digits.append(UInt8(count))
}
while quotient.digits.count > 1 && quotient.digits.last == 0 {
quotient.digits.removeLast()
}
return (BigInt(digits: quotient.digits.reversed()), remainder)
}
private func toIntSafe() -> Int {
var value = 0
for digit in digits.reversed() { value = value * 10 + Int(digit) }
return value
}
}
