├── .codecov.yml ├── .github └── workflows │ ├── jazzy.yml │ └── swift.yml ├── .gitignore ├── .jazzy.yml ├── .spi.yml ├── CHANGELOG.md ├── Demo.playground ├── Contents.o ├── Pages │ ├── Digits of Pi.xcplaygroundpage │ │ ├── Contents.swift │ │ └── timeline.xctimeline │ ├── Factorials.xcplaygroundpage │ │ └── Contents.swift │ ├── Generating Large Primes.xcplaygroundpage │ │ └── Contents.swift │ ├── Introduction.xcplaygroundpage │ │ └── Contents.swift │ └── The RSA algorithm.xcplaygroundpage │ │ ├── Contents.swift │ │ └── timeline.xctimeline └── contents.xcplayground ├── LICENSE.md ├── Package.swift ├── README.md ├── Sources ├── Addition.swift ├── BigInt.swift ├── BigUInt.swift ├── Bitwise Ops.swift ├── Codable.swift ├── Comparable.swift ├── Data Conversion.swift ├── Division.swift ├── Exponentiation.swift ├── Floating Point Conversion.swift ├── GCD.swift ├── Hashable.swift ├── Integer Conversion.swift ├── Multiplication.swift ├── Prime Test.swift ├── Random.swift ├── Shifts.swift ├── Square Root.swift ├── Strideable.swift ├── String Conversion.swift ├── Subtraction.swift └── Words and Bits.swift ├── Tests └── BigIntTests │ ├── BigIntTests.swift │ ├── BigUIntTests.swift │ ├── ProfileTests.swift │ ├── Tools.swift │ ├── Violet - Helpers │ ├── BitWidthTestCases.swift │ ├── GenerateValues.swift │ ├── GlobalFunctions.swift │ ├── StringTestCases.swift │ └── WordsTestCases.swift │ ├── Violet - Property testing │ ├── ApplyA_ApplyB_Equals_ApplyAB.swift │ └── ApplyA_UndoA.swift │ ├── Violet │ ├── BigIntCOWTests.swift │ ├── BigIntHashTests.swift │ ├── BigIntIntegerInitTests.swift │ ├── BigIntPowerTests.swift │ ├── BigIntPropertyTests.swift │ └── BigIntStringInitTests.swift │ └── WordTests.swift ├── docs ├── Extensions.html ├── Extensions │ ├── BinaryFloatingPoint.html │ └── String.html ├── Structs.html ├── Structs │ ├── BigInt.html │ ├── BigInt │ │ ├── Sign.html │ │ └── Words.html │ ├── BigUInt.html │ └── BigUInt │ │ └── Words.html ├── badge.svg ├── css │ ├── highlight.css │ └── jazzy.css ├── docsets │ ├── BigInt.docset │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ ├── Documents │ │ │ ├── Extensions.html │ │ │ ├── Extensions │ │ │ │ ├── BinaryFloatingPoint.html │ │ │ │ └── String.html │ │ │ ├── Structs.html │ │ │ ├── Structs │ │ │ │ ├── BigInt.html │ │ │ │ ├── BigInt │ │ │ │ │ ├── Sign.html │ │ │ │ │ └── Words.html │ │ │ │ ├── BigUInt.html │ │ │ │ └── BigUInt │ │ │ │ │ └── Words.html │ │ │ ├── css │ │ │ │ ├── highlight.css │ │ │ │ └── jazzy.css │ │ │ ├── img │ │ │ │ ├── carat.png │ │ │ │ ├── dash.png │ │ │ │ ├── gh.png │ │ │ │ └── spinner.gif │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── jazzy.js │ │ │ │ ├── jazzy.search.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── lunr.min.js │ │ │ │ └── typeahead.jquery.js │ │ │ └── search.json │ │ │ └── docSet.dsidx │ ├── BigInt.tgz │ └── BigInt.xml ├── img │ ├── carat.png │ ├── dash.png │ ├── gh.png │ └── spinner.gif ├── index.html ├── js │ ├── jazzy.js │ ├── jazzy.search.js │ ├── jquery.min.js │ ├── lunr.min.js │ └── typeahead.jquery.js ├── search.json └── undocumented.json └── images ├── BigInt.sketch └── banner.png /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "/Tests/*" 3 | comment: 4 | layout: "header, diff" 5 | behavior: default 6 | require_changes: no 7 | coverage: 8 | status: 9 | project: 10 | default: 11 | target: auto 12 | threshold: null 13 | base: auto 14 | paths: "Sources/*" 15 | -------------------------------------------------------------------------------- /.github/workflows/jazzy.yml: -------------------------------------------------------------------------------- 1 | name: Swift 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | macos: 10 | runs-on: macos-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Install jazzy 14 | run: gem install jazzy 15 | - name: Generate documentation 16 | run: | 17 | jazzy \ 18 | --clean \ 19 | --github-file-prefix "https://github.com/attaswift/$module/tree/${GITHUB_REF}" \ 20 | --module-version "${{ github.event.release.tag_name }}" \ 21 | --copyright "© $(date '+%Y') [Károly Lőrentey](https://twitter.com/lorentey). (Last updated: $(date '+%Y-%m-%d'))" \ 22 | --config .jazzy.yml 23 | - name: Commit docs 24 | run: | 25 | git config --local user.email "bot@github.com" 26 | git config --local user.name "GitHub Actions" 27 | git add ./docs 28 | git commit -m "Update docs" 29 | git push origin HEAD:master 30 | -------------------------------------------------------------------------------- /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: Swift 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | 8 | jobs: 9 | macos: 10 | runs-on: macos-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Build 14 | run: swift build --build-tests 15 | - name: Run tests 16 | run: swift test --parallel 17 | 18 | linux: 19 | container: 20 | image: swift:${{ matrix.linux }} 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | linux: [focal, jammy, noble] 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Build 28 | run: swift build --build-tests --enable-test-discovery 29 | - name: Test 30 | run: swift test --enable-test-discovery --parallel 31 | 32 | android: 33 | runs-on: macos-13 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@v4 37 | - name: Setup Environment 38 | run: echo "ANDROID_NDK_HOME=${HOME}/Library/Android/sdk/ndk/27.2.12479018" >> $GITHUB_ENV 39 | - name: Test 40 | uses: skiptools/swift-android-action@v2 41 | 42 | # codecov: 43 | # runs-on: macos-latest 44 | # steps: 45 | # - uses: actions/checkout@v4 46 | # - name: Test and generate code coverage report 47 | # run: swift test --enable-code-coverage 48 | # - name: Upload coverage to Codecov 49 | # uses: codecov/codecov-action@v4 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Carthage/Build 2 | /.build 3 | /Packages 4 | xcuserdata 5 | /Package.pins 6 | /Package.resolved 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.jazzy.yml: -------------------------------------------------------------------------------- 1 | module: BigInt 2 | author: Károly Lőrentey 3 | theme: fullwidth 4 | output: ./docs 5 | author_url: "https://twitter.com/lorentey" 6 | github_url: "https://github.com/attaswift/BigInt" 7 | root_url: "https://attaswift.github.io/BigInt/reference/" 8 | xcodebuild_arguments: ["-workspace", "BigInt.xcworkspace", "-scheme", "BigInt-macOS"] -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | external_links: 3 | documentation: "https://attaswift.github.io/BigInt/" 4 | -------------------------------------------------------------------------------- /Demo.playground/Contents.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/Demo.playground/Contents.o -------------------------------------------------------------------------------- /Demo.playground/Pages/Digits of Pi.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | import BigInt 3 | //: ## Let's calculate the first thousand digits of π 4 | //: 5 | //: A fun application of BigInts is generating the digits of π. 6 | //: Let's implement [Jeremy Gibbon's spigot algorithm][spigot] as an infinite `GeneratorType`. 7 | //: This is a quite slow algorithm, but it makes up for it with its grooviness factor. 8 | //: 9 | //: [spigot]: http://www.cs.ox.ac.uk/jeremy.gibbons/publications/spigot.pdf 10 | func digitsOfPi() -> AnyIterator { 11 | var q: BigUInt = 1 12 | var r: BigUInt = 180 13 | var t: BigUInt = 60 14 | var i: UInt = 2 // Works until digit #826_566_842 15 | return AnyIterator { 16 | let u: UInt = 3 * (3 * i + 1) * (3 * i + 2) 17 | let y = (q.multiplied(byWord: 27 * i - 12) + 5 * r) / (5 * t) 18 | (q, r, t) = ( 19 | 10 * q.multiplied(byWord: i * (2 * i - 1)), 20 | 10 * (q.multiplied(byWord: 5 * i - 2) + r - y * t).multiplied(byWord: u), 21 | t.multiplied(byWord: u)) 22 | i += 1 23 | return Int(y.words[0]) 24 | } 25 | } 26 | //: Well, that was surprisingly easy. Does it work? You bet: 27 | let digits = digitsOfPi().prefix(999).reduce("") { $0 + String($1) } 28 | //: [Next](@next) 29 | -------------------------------------------------------------------------------- /Demo.playground/Pages/Digits of Pi.xcplaygroundpage/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 20 | 21 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Demo.playground/Pages/Factorials.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | import Foundation 3 | import BigInt 4 | //: The canonical way to demo big integers is with the factorial function. Here is a fancy definition for it: 5 | func fact(_ n: Int) -> BigInt { 6 | return (1 ... n).map { BigInt($0) }.reduce(BigInt(1), *) 7 | } 8 | 9 | let f1 = fact(1) 10 | let f2 = fact(2) 11 | let f3 = fact(3) 12 | let f4 = fact(4) 13 | let f10 = fact(10) 14 | let f100 = fact(100) 15 | let f1000 = fact(1000) 16 | //: That last value seems quite large. Just how many decimal digits is it? Let's convert it to a `String` to find out. 17 | let decimal = String(f1000) 18 | let digitCount = decimal.count 19 | //: Wow. 2500 digits is peanuts for `BigInt`, but Xcode's playground tech isn't designed to perform well with much more loop iterations, so let's stay at this level for now. 20 | let ff2 = f1000 * f1000 21 | String(ff2).count 22 | 23 | let ff4 = ff2 * ff2 24 | String(ff4).count 25 | 26 | let ff8 = ff4 * ff4 27 | String(ff8).count 28 | //: That last operation multiplied two 10000-digit numbers; you may have noticed it took a couple of seconds to compute that value. Converting such huge values to decimal isn't particularly cheap, either. 29 | //: 30 | //: [Next](@next) 31 | -------------------------------------------------------------------------------- /Demo.playground/Pages/Generating Large Primes.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | import Foundation 3 | import BigInt 4 | //: # Generating Large Prime Numbers 5 | //: 6 | //: `BigUInt` has an `isPrime()` method that does a [Miller-Rabin Primality Test][mrpt]. Let's use 7 | //: this to create a function that finds the next prime number after any integer: 8 | //: 9 | //: [mrpt]: https://en.wikipedia.org/wiki/Miller%2dRabin_primality_test 10 | func findNextPrime(after integer: BigUInt) -> BigUInt { 11 | var candidate = integer 12 | repeat { 13 | candidate += 1 14 | } while !candidate.isPrime() 15 | return candidate 16 | } 17 | 18 | findNextPrime(after: 100) 19 | findNextPrime(after: 1000) 20 | findNextPrime(after: 10000) 21 | findNextPrime(after: 100000000000) 22 | findNextPrime(after: BigUInt(1) << 64) 23 | findNextPrime(after: BigUInt(1) << 128) 24 | findNextPrime(after: BigUInt(1) << 256) 25 | //: [Next](@next) 26 | -------------------------------------------------------------------------------- /Demo.playground/Pages/Introduction.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: # Introduction 2 | //: 3 | //: The `BigInt` module provides a `BigInt` type that implements an [https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic](integer type of arbitrary width). 4 | //: These work much like `Int`s, but they don't have a preset maximum value---so they will never overflow. 5 | //: The only practical limit to their capacity is the amount of memory & address space that your computer has, and the 6 | //: amount of time you're willing to spend waiting for results---when their operands are truly huge, 7 | //: big integer operations can take a long time to execute. 8 | //: (`BigInt` represents integers in base 2^64, storing digits in an `Array`, so the theoretical 9 | //: maximum value it can store is (2^64)^`Int.max` - 1.) 10 | import Foundation 11 | import BigInt 12 | //: `BigInt` has several interesting initializers, but for now, the simplest way to create big integers is to use integer 13 | //: or string literals. The latter is useful when you want to create a number that's larger than `UIntMax.max`: 14 | let a: BigInt = 123 15 | let b: BigInt = 12345678 16 | let c: BigInt = 1234567890123456 17 | let d: BigInt = "12345678901234567890123456789012345678901234567890123456789012345678" 18 | //: To work with `BigInt`s, you use the same arithmetic operators as you do with everyday `Int` values: 19 | a + b 20 | b - a 21 | -b 22 | a * b 23 | a * b * c 24 | a * b * c * d 25 | 26 | d / c 27 | d % c 28 | d / (c * c) 29 | d / (c * c * c) 30 | d / (c * c * c * c) 31 | //: [Next](@next) 32 | -------------------------------------------------------------------------------- /Demo.playground/Pages/The RSA algorithm.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | import Foundation 3 | import BigInt 4 | //: # RSA cryptography 5 | //: 6 | //: Another useful thing to have is a function that finds a random n-bit prime number: 7 | func generatePrime(ofWidth width: Int) -> BigUInt { 8 | while true { 9 | var random = BigUInt.randomInteger(withExactWidth: width) 10 | random |= BigUInt(1) 11 | if random.isPrime() { 12 | return random 13 | } 14 | } 15 | } 16 | //: For instance, here are two random 1024-bit prime numbers: 17 | let p = generatePrime(ofWidth: 1024) 18 | let q = generatePrime(ofWidth: 1024) 19 | //: We know their product isn't prime, and `BigInt`'s primality test agrees: 20 | let n = p * q 21 | n.isPrime() 22 | //: But we'd be in serious trouble if we had to get `p` and `q` back by factoring `n`---and this observation is 23 | //: what makes RSA work. 24 | //: 25 | //: So let's derive a public/private RSA keypair out of these two primes: 26 | //: 27 | //: (Note though that in a real RSA cryptosystem, primes are chosen much more carefully.) 28 | let phi = (p - 1) * (q - 1) 29 | let e: BigUInt = 65537 30 | let d = e.inverse(phi)! 31 | 32 | d * e % phi 33 | 34 | typealias Key = (modulus: BigUInt, exponent: BigUInt) 35 | 36 | let publicKey: Key = (n, e) 37 | let privateKey: Key = (n, d) 38 | //: Given a key and a message, encryption is simply a modular exponentiation: 39 | //: (Again, this is an oversimplification. In the real RSA system, the message is first transformed by a 40 | //: [complex padding scheme][oaep].) 41 | //: 42 | //: [oaep]: https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding 43 | func encrypt(_ message: BigUInt, key: Key) -> BigUInt { 44 | return message.power(key.exponent, modulus: key.modulus) 45 | } 46 | //: Let's try encrypting some message with the public key. 47 | let secret: BigUInt = BigUInt("Arbitrary precision arithmetic is fun!".data(using: .utf8)!) 48 | 49 | let cyphertext = encrypt(secret, key: publicKey) 50 | //: Well that was easy. In theory, we can decrypt the cyphertext by simply encrypting it with the private key. 51 | //: But does it really work? Yep: 52 | let plaintext = encrypt(cyphertext, key: privateKey) 53 | 54 | let message = String(data: plaintext.serialize(), encoding: .utf8) 55 | //: Isn't that awesome? 56 | //: 57 | //: [Next](@next) 58 | -------------------------------------------------------------------------------- /Demo.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016-2017 Károly Lőrentey 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.9 2 | // 3 | // Package.swift 4 | // BigInt 5 | // 6 | // Created by Károly Lőrentey on 2016-01-12. 7 | // Copyright © 2016-2017 Károly Lőrentey. 8 | // 9 | 10 | import PackageDescription 11 | 12 | let package = Package( 13 | name: "BigInt", 14 | platforms: [ 15 | .macOS(.v10_13), 16 | .iOS(.v12), 17 | .tvOS(.v12), 18 | .watchOS(.v4), 19 | .macCatalyst(.v13), 20 | .visionOS(.v1), 21 | ], 22 | products: [ 23 | .library(name: "BigInt", targets: ["BigInt"]) 24 | ], 25 | targets: [ 26 | .target(name: "BigInt", path: "Sources"), 27 | .testTarget(name: "BigIntTests", dependencies: ["BigInt"], path: "Tests") 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /Sources/Addition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Addition.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | //MARK: Addition 11 | 12 | /// Add `word` to this integer in place. 13 | /// `word` is shifted `shift` words to the left before being added. 14 | /// 15 | /// - Complexity: O(max(count, shift)) 16 | internal mutating func addWord(_ word: Word, shiftedBy shift: Int = 0) { 17 | precondition(shift >= 0) 18 | var carry = word 19 | var i = shift 20 | while carry > 0 { 21 | let (d, c) = self[i].addingReportingOverflow(carry) 22 | self[i] = d 23 | carry = (c ? 1 : 0) 24 | i += 1 25 | } 26 | } 27 | 28 | /// Add the digit `d` to this integer and return the result. 29 | /// `d` is shifted `shift` words to the left before being added. 30 | /// 31 | /// - Complexity: O(max(count, shift)) 32 | internal func addingWord(_ word: Word, shiftedBy shift: Int = 0) -> BigUInt { 33 | var r = self 34 | r.addWord(word, shiftedBy: shift) 35 | return r 36 | } 37 | 38 | /// Add `b` to this integer in place. 39 | /// `b` is shifted `shift` words to the left before being added. 40 | /// 41 | /// - Complexity: O(max(count, b.count + shift)) 42 | internal mutating func add(_ b: BigUInt, shiftedBy shift: Int = 0) { 43 | precondition(shift >= 0) 44 | var carry = false 45 | var bi = 0 46 | let bc = b.count 47 | while bi < bc || carry { 48 | let ai = shift + bi 49 | let (d, c) = self[ai].addingReportingOverflow(b[bi]) 50 | if carry { 51 | let (d2, c2) = d.addingReportingOverflow(1) 52 | self[ai] = d2 53 | carry = c || c2 54 | } 55 | else { 56 | self[ai] = d 57 | carry = c 58 | } 59 | bi += 1 60 | } 61 | } 62 | 63 | /// Add `b` to this integer and return the result. 64 | /// `b` is shifted `shift` words to the left before being added. 65 | /// 66 | /// - Complexity: O(max(count, b.count + shift)) 67 | internal func adding(_ b: BigUInt, shiftedBy shift: Int = 0) -> BigUInt { 68 | var r = self 69 | r.add(b, shiftedBy: shift) 70 | return r 71 | } 72 | 73 | /// Increment this integer by one. If `shift` is non-zero, it selects 74 | /// the word that is to be incremented. 75 | /// 76 | /// - Complexity: O(count + shift) 77 | internal mutating func increment(shiftedBy shift: Int = 0) { 78 | self.addWord(1, shiftedBy: shift) 79 | } 80 | 81 | /// Add `a` and `b` together and return the result. 82 | /// 83 | /// - Complexity: O(max(a.count, b.count)) 84 | public static func +(a: BigUInt, b: BigUInt) -> BigUInt { 85 | return a.adding(b) 86 | } 87 | 88 | /// Add `a` and `b` together, and store the sum in `a`. 89 | /// 90 | /// - Complexity: O(max(a.count, b.count)) 91 | public static func +=(a: inout BigUInt, b: BigUInt) { 92 | a.add(b, shiftedBy: 0) 93 | } 94 | } 95 | 96 | extension BigInt { 97 | /// Add `a` to `b` and return the result. 98 | public static func +(a: BigInt, b: BigInt) -> BigInt { 99 | switch (a.sign, b.sign) { 100 | case (.plus, .plus): 101 | return BigInt(sign: .plus, magnitude: a.magnitude + b.magnitude) 102 | case (.minus, .minus): 103 | return BigInt(sign: .minus, magnitude: a.magnitude + b.magnitude) 104 | case (.plus, .minus): 105 | if a.magnitude >= b.magnitude { 106 | return BigInt(sign: .plus, magnitude: a.magnitude - b.magnitude) 107 | } 108 | else { 109 | return BigInt(sign: .minus, magnitude: b.magnitude - a.magnitude) 110 | } 111 | case (.minus, .plus): 112 | if b.magnitude >= a.magnitude { 113 | return BigInt(sign: .plus, magnitude: b.magnitude - a.magnitude) 114 | } 115 | else { 116 | return BigInt(sign: .minus, magnitude: a.magnitude - b.magnitude) 117 | } 118 | } 119 | } 120 | 121 | /// Add `b` to `a` in place. 122 | public static func +=(a: inout BigInt, b: BigInt) { 123 | a = a + b 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /Sources/BigInt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BigInt.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2015-12-27. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | //MARK: BigInt 10 | 11 | /// An arbitary precision signed integer type, also known as a "big integer". 12 | /// 13 | /// Operations on big integers never overflow, but they might take a long time to execute. 14 | /// The amount of memory (and address space) available is the only constraint to the magnitude of these numbers. 15 | /// 16 | /// This particular big integer type uses base-2^64 digits to represent integers. 17 | /// 18 | /// `BigInt` is essentially a tiny wrapper that extends `BigUInt` with a sign bit and provides signed integer 19 | /// operations. Both the underlying absolute value and the negative/positive flag are available as read-write 20 | /// properties. 21 | /// 22 | /// Not all algorithms of `BigUInt` are available for `BigInt` values; for example, there is no square root or 23 | /// primality test for signed integers. When you need to call one of these, just extract the absolute value: 24 | /// 25 | /// ```Swift 26 | /// BigInt(255).magnitude.isPrime() // Returns false 27 | /// ``` 28 | /// 29 | public struct BigInt: SignedInteger, Sendable { 30 | public enum Sign: Sendable { 31 | case plus 32 | case minus 33 | } 34 | 35 | public typealias Magnitude = BigUInt 36 | 37 | /// The type representing a digit in `BigInt`'s underlying number system. 38 | public typealias Word = BigUInt.Word 39 | 40 | public static var isSigned: Bool { 41 | return true 42 | } 43 | 44 | /// The absolute value of this integer. 45 | public var magnitude: BigUInt 46 | 47 | /// True iff the value of this integer is negative. 48 | public var sign: Sign 49 | 50 | /// Initializes a new big integer with the provided absolute number and sign flag. 51 | public init(sign: Sign, magnitude: BigUInt) { 52 | self.sign = (magnitude.isZero ? .plus : sign) 53 | self.magnitude = magnitude 54 | } 55 | 56 | /// Return true iff this integer is zero. 57 | /// 58 | /// - Complexity: O(1) 59 | public var isZero: Bool { 60 | return magnitude.isZero 61 | } 62 | 63 | /// Returns `-1` if this value is negative and `1` if it’s positive; otherwise, `0`. 64 | /// 65 | /// - Returns: The sign of this number, expressed as an integer of the same type. 66 | public func signum() -> BigInt { 67 | switch sign { 68 | case .plus: 69 | return isZero ? 0 : 1 70 | case .minus: 71 | return -1 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/Bitwise Ops.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bitwise Ops.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | //MARK: Bitwise Operations 10 | 11 | extension BigUInt { 12 | /// Return the ones' complement of `a`. 13 | /// 14 | /// - Complexity: O(a.count) 15 | public static prefix func ~(a: BigUInt) -> BigUInt { 16 | return BigUInt(words: a.words.map { ~$0 }) 17 | } 18 | 19 | /// Calculate the bitwise OR of `a` and `b`, and store the result in `a`. 20 | /// 21 | /// - Complexity: O(max(a.count, b.count)) 22 | public static func |= (a: inout BigUInt, b: BigUInt) { 23 | a.reserveCapacity(b.count) 24 | for i in 0 ..< b.count { 25 | a[i] |= b[i] 26 | } 27 | } 28 | 29 | /// Calculate the bitwise AND of `a` and `b` and return the result. 30 | /// 31 | /// - Complexity: O(max(a.count, b.count)) 32 | public static func &= (a: inout BigUInt, b: BigUInt) { 33 | for i in 0 ..< Swift.max(a.count, b.count) { 34 | a[i] &= b[i] 35 | } 36 | } 37 | 38 | /// Calculate the bitwise XOR of `a` and `b` and return the result. 39 | /// 40 | /// - Complexity: O(max(a.count, b.count)) 41 | public static func ^= (a: inout BigUInt, b: BigUInt) { 42 | a.reserveCapacity(b.count) 43 | for i in 0 ..< b.count { 44 | a[i] ^= b[i] 45 | } 46 | } 47 | } 48 | 49 | extension BigInt { 50 | public static prefix func ~(x: BigInt) -> BigInt { 51 | switch x.sign { 52 | case .plus: 53 | return BigInt(sign: .minus, magnitude: x.magnitude + 1) 54 | case .minus: 55 | return BigInt(sign: .plus, magnitude: x.magnitude - 1) 56 | } 57 | } 58 | 59 | public static func &(lhs: inout BigInt, rhs: BigInt) -> BigInt { 60 | let left = lhs.words 61 | let right = rhs.words 62 | // Note we aren't using left.count/right.count here; we account for the sign bit separately later. 63 | let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) 64 | var words: [UInt] = [] 65 | words.reserveCapacity(count) 66 | for i in 0 ..< count { 67 | words.append(left[i] & right[i]) 68 | } 69 | if lhs.sign == .minus && rhs.sign == .minus { 70 | words.twosComplement() 71 | return BigInt(sign: .minus, magnitude: BigUInt(words: words)) 72 | } 73 | return BigInt(sign: .plus, magnitude: BigUInt(words: words)) 74 | } 75 | 76 | public static func |(lhs: inout BigInt, rhs: BigInt) -> BigInt { 77 | let left = lhs.words 78 | let right = rhs.words 79 | // Note we aren't using left.count/right.count here; we account for the sign bit separately later. 80 | let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) 81 | var words: [UInt] = [] 82 | words.reserveCapacity(count) 83 | for i in 0 ..< count { 84 | words.append(left[i] | right[i]) 85 | } 86 | if lhs.sign == .minus || rhs.sign == .minus { 87 | words.twosComplement() 88 | return BigInt(sign: .minus, magnitude: BigUInt(words: words)) 89 | } 90 | return BigInt(sign: .plus, magnitude: BigUInt(words: words)) 91 | } 92 | 93 | public static func ^(lhs: inout BigInt, rhs: BigInt) -> BigInt { 94 | let left = lhs.words 95 | let right = rhs.words 96 | // Note we aren't using left.count/right.count here; we account for the sign bit separately later. 97 | let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) 98 | var words: [UInt] = [] 99 | words.reserveCapacity(count) 100 | for i in 0 ..< count { 101 | words.append(left[i] ^ right[i]) 102 | } 103 | if (lhs.sign == .minus) != (rhs.sign == .minus) { 104 | words.twosComplement() 105 | return BigInt(sign: .minus, magnitude: BigUInt(words: words)) 106 | } 107 | return BigInt(sign: .plus, magnitude: BigUInt(words: words)) 108 | } 109 | 110 | public static func &=(lhs: inout BigInt, rhs: BigInt) { 111 | lhs = lhs & rhs 112 | } 113 | 114 | public static func |=(lhs: inout BigInt, rhs: BigInt) { 115 | lhs = lhs | rhs 116 | } 117 | 118 | public static func ^=(lhs: inout BigInt, rhs: BigInt) { 119 | lhs = lhs ^ rhs 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Sources/Codable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Codable.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-8-11. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | 10 | // Little-endian to big-endian 11 | struct Units: RandomAccessCollection 12 | where Words.Element: FixedWidthInteger, Words.Index == Int { 13 | typealias Word = Words.Element 14 | let words: Words 15 | init(of type: Unit.Type, _ words: Words) { 16 | precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0) 17 | self.words = words 18 | } 19 | var count: Int { return (words.count * Word.bitWidth + Unit.bitWidth - 1) / Unit.bitWidth } 20 | var startIndex: Int { return 0 } 21 | var endIndex: Int { return count } 22 | subscript(_ index: Int) -> Unit { 23 | let index = count - 1 - index 24 | if Unit.bitWidth == Word.bitWidth { 25 | return Unit(words[index]) 26 | } 27 | else if Unit.bitWidth > Word.bitWidth { 28 | let c = Unit.bitWidth / Word.bitWidth 29 | var unit: Unit = 0 30 | var j = 0 31 | for i in (c * index) ..< Swift.min(c * (index + 1), words.endIndex) { 32 | unit |= Unit(words[i]) << j 33 | j += Word.bitWidth 34 | } 35 | return unit 36 | } 37 | // Unit.bitWidth < Word.bitWidth 38 | let c = Word.bitWidth / Unit.bitWidth 39 | let i = index / c 40 | let j = index % c 41 | return Unit(truncatingIfNeeded: words[i] >> (j * Unit.bitWidth)) 42 | } 43 | } 44 | 45 | extension Array where Element: FixedWidthInteger { 46 | // Big-endian to little-endian 47 | init(count: Int?, generator: () throws -> Unit?) rethrows { 48 | typealias Word = Element 49 | precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0) 50 | self = [] 51 | if Unit.bitWidth == Word.bitWidth { 52 | if let count = count { 53 | self.reserveCapacity(count) 54 | } 55 | while let unit = try generator() { 56 | self.append(Word(unit)) 57 | } 58 | } 59 | else if Unit.bitWidth > Word.bitWidth { 60 | let wordsPerUnit = Unit.bitWidth / Word.bitWidth 61 | if let count = count { 62 | self.reserveCapacity(count * wordsPerUnit) 63 | } 64 | while let unit = try generator() { 65 | var shift = Unit.bitWidth - Word.bitWidth 66 | while shift >= 0 { 67 | self.append(Word(truncatingIfNeeded: unit >> shift)) 68 | shift -= Word.bitWidth 69 | } 70 | } 71 | } 72 | else { 73 | let unitsPerWord = Word.bitWidth / Unit.bitWidth 74 | if let count = count { 75 | self.reserveCapacity((count + unitsPerWord - 1) / unitsPerWord) 76 | } 77 | var word: Word = 0 78 | var c = 0 79 | while let unit = try generator() { 80 | word <<= Unit.bitWidth 81 | word |= Word(unit) 82 | c += Unit.bitWidth 83 | if c == Word.bitWidth { 84 | self.append(word) 85 | word = 0 86 | c = 0 87 | } 88 | } 89 | if c > 0 { 90 | self.append(word << c) 91 | var shifted: Word = 0 92 | for i in self.indices { 93 | let word = self[i] 94 | self[i] = shifted | (word >> c) 95 | shifted = word << (Word.bitWidth - c) 96 | } 97 | } 98 | } 99 | self.reverse() 100 | } 101 | } 102 | 103 | extension BigInt: Codable { 104 | public init(from decoder: Decoder) throws { 105 | if let container = try? decoder.singleValueContainer(), let stringValue = try? container.decode(String.self) { 106 | if stringValue.hasPrefix("0x") || stringValue.hasPrefix("0X") { 107 | guard let bigUInt = BigUInt(stringValue.dropFirst(2), radix: 16) else { 108 | throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid hexadecimal BigInt string") 109 | } 110 | self.init(sign: .plus, magnitude: bigUInt) 111 | } else { 112 | guard let bigInt = BigInt(stringValue) else { 113 | throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid decimal BigInt string") 114 | } 115 | self = bigInt 116 | } 117 | } else { 118 | var container = try decoder.unkeyedContainer() 119 | 120 | // Decode sign 121 | let sign: BigInt.Sign 122 | switch try container.decode(String.self) { 123 | case "+": 124 | sign = .plus 125 | case "-": 126 | sign = .minus 127 | default: 128 | throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, 129 | debugDescription: "Invalid big integer sign")) 130 | } 131 | 132 | // Decode magnitude 133 | let words = try [UInt](count: container.count?.advanced(by: -1)) { () -> UInt64? in 134 | guard !container.isAtEnd else { return nil } 135 | return try container.decode(UInt64.self) 136 | } 137 | let magnitude = BigUInt(words: words) 138 | 139 | self.init(sign: sign, magnitude: magnitude) 140 | } 141 | } 142 | 143 | public func encode(to encoder: Encoder) throws { 144 | var container = encoder.unkeyedContainer() 145 | try container.encode(sign == .plus ? "+" : "-") 146 | let units = Units(of: UInt64.self, self.magnitude.words) 147 | if units.isEmpty { 148 | try container.encode(0 as UInt64) 149 | } 150 | else { 151 | try container.encode(contentsOf: units) 152 | } 153 | } 154 | } 155 | 156 | extension BigUInt: Codable { 157 | public init(from decoder: Decoder) throws { 158 | let value = try BigInt(from: decoder) 159 | guard value.sign == .plus else { 160 | throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, 161 | debugDescription: "BigUInt cannot hold a negative value")) 162 | } 163 | self = value.magnitude 164 | } 165 | 166 | public func encode(to encoder: Encoder) throws { 167 | try BigInt(sign: .plus, magnitude: self).encode(to: encoder) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Sources/Comparable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comparable.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | #if canImport(Foundation) 10 | import Foundation 11 | #endif 12 | 13 | extension BigUInt: Comparable { 14 | #if !canImport(Foundation) 15 | public enum ComparisonResult: Sendable, Comparable, Hashable { 16 | case orderedDescending 17 | case orderedSame 18 | case orderedAscending 19 | } 20 | #endif 21 | 22 | //MARK: Comparison 23 | 24 | /// Compare `a` to `b` and return an `NSComparisonResult` indicating their order. 25 | /// 26 | /// - Complexity: O(count) 27 | public static func compare(_ a: BigUInt, _ b: BigUInt) -> ComparisonResult { 28 | if a.count != b.count { return a.count > b.count ? .orderedDescending : .orderedAscending } 29 | for i in (0 ..< a.count).reversed() { 30 | let ad = a[i] 31 | let bd = b[i] 32 | if ad != bd { return ad > bd ? .orderedDescending : .orderedAscending } 33 | } 34 | return .orderedSame 35 | } 36 | 37 | /// Return true iff `a` is equal to `b`. 38 | /// 39 | /// - Complexity: O(count) 40 | public static func ==(a: BigUInt, b: BigUInt) -> Bool { 41 | return BigUInt.compare(a, b) == .orderedSame 42 | } 43 | 44 | /// Return true iff `a` is less than `b`. 45 | /// 46 | /// - Complexity: O(count) 47 | public static func <(a: BigUInt, b: BigUInt) -> Bool { 48 | return BigUInt.compare(a, b) == .orderedAscending 49 | } 50 | } 51 | 52 | extension BigInt: Comparable { 53 | /// Return true iff `a` is equal to `b`. 54 | public static func ==(a: BigInt, b: BigInt) -> Bool { 55 | return a.sign == b.sign && a.magnitude == b.magnitude 56 | } 57 | 58 | /// Return true iff `a` is less than `b`. 59 | public static func <(a: BigInt, b: BigInt) -> Bool { 60 | switch (a.sign, b.sign) { 61 | case (.plus, .plus): 62 | return a.magnitude < b.magnitude 63 | case (.plus, .minus): 64 | return false 65 | case (.minus, .plus): 66 | return true 67 | case (.minus, .minus): 68 | return a.magnitude > b.magnitude 69 | } 70 | } 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /Sources/Data Conversion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data Conversion.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-04. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | #if canImport(Foundation) 10 | import Foundation 11 | #endif 12 | 13 | extension BigUInt { 14 | //MARK: NSData Conversion 15 | 16 | /// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer 17 | public init(_ buffer: UnsafeRawBufferPointer) { 18 | // This assumes Word is binary. 19 | precondition(Word.bitWidth % 8 == 0) 20 | 21 | self.init() 22 | 23 | let length = buffer.count 24 | guard length > 0 else { return } 25 | let bytesPerDigit = Word.bitWidth / 8 26 | var index = length / bytesPerDigit 27 | var c = bytesPerDigit - length % bytesPerDigit 28 | if c == bytesPerDigit { 29 | c = 0 30 | index -= 1 31 | } 32 | 33 | var word: Word = 0 34 | for byte in buffer { 35 | word <<= 8 36 | word += Word(byte) 37 | c += 1 38 | if c == bytesPerDigit { 39 | self[index] = word 40 | index -= 1 41 | c = 0 42 | word = 0 43 | } 44 | } 45 | assert(c == 0 && word == 0 && index == -1) 46 | } 47 | 48 | /// Return a `UnsafeRawBufferPointer` buffer that contains the base-256 representation of this integer, in network (big-endian) byte order. 49 | public func serializeToBuffer() -> UnsafeRawBufferPointer { 50 | // This assumes Digit is binary. 51 | precondition(Word.bitWidth % 8 == 0) 52 | 53 | let byteCount = (self.bitWidth + 7) / 8 54 | 55 | let buffer = UnsafeMutableBufferPointer.allocate(capacity: byteCount) 56 | 57 | guard byteCount > 0 else { return UnsafeRawBufferPointer(start: buffer.baseAddress, count: 0) } 58 | 59 | var i = byteCount - 1 60 | for var word in self.words { 61 | for _ in 0 ..< Word.bitWidth / 8 { 62 | buffer[i] = UInt8(word & 0xFF) 63 | word >>= 8 64 | if i == 0 { 65 | assert(word == 0) 66 | break 67 | } 68 | i -= 1 69 | } 70 | } 71 | let zeroOut = UnsafeMutableBufferPointer(start: buffer.baseAddress, count: i) 72 | zeroOut.initialize(repeating: 0) 73 | return UnsafeRawBufferPointer(start: buffer.baseAddress, count: byteCount) 74 | } 75 | 76 | #if canImport(Foundation) 77 | /// Initializes an integer from the bits stored inside a piece of `Data`. 78 | /// The data is assumed to be in network (big-endian) byte order. 79 | public init(_ data: Data) { 80 | self = data.withUnsafeBytes({ buffer in 81 | BigUInt(buffer) 82 | }) 83 | } 84 | 85 | /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order. 86 | public func serialize() -> Data { 87 | let buffer = serializeToBuffer() 88 | defer { buffer.deallocate() } 89 | guard 90 | let pointer = buffer.baseAddress.map(UnsafeMutableRawPointer.init(mutating:)) 91 | else { return Data() } 92 | 93 | return Data(bytes: pointer, count: buffer.count) 94 | } 95 | #endif 96 | } 97 | 98 | extension BigInt { 99 | 100 | /// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer, 101 | /// where the first byte indicates sign (0 for positive, 1 for negative) 102 | public init(_ buffer: UnsafeRawBufferPointer) { 103 | // This assumes Word is binary. 104 | precondition(Word.bitWidth % 8 == 0) 105 | 106 | self.init() 107 | 108 | let length = buffer.count 109 | 110 | // Serialized data for a BigInt should contain at least 2 bytes: one representing 111 | // the sign, and another for the non-zero magnitude. Zero is represented by an 112 | // empty Data struct, and negative zero is not supported. 113 | guard length > 1, let firstByte = buffer.first else { return } 114 | 115 | // The first byte gives the sign 116 | // This byte is compared to a bitmask to allow additional functionality to be added 117 | // to this byte in the future. 118 | self.sign = firstByte & 0b1 == 0 ? .plus : .minus 119 | 120 | self.magnitude = BigUInt(UnsafeRawBufferPointer(rebasing: buffer.dropFirst(1))) 121 | } 122 | 123 | /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative) 124 | public func serializeToBuffer() -> UnsafeRawBufferPointer { 125 | // Create a data object for the magnitude portion of the BigInt 126 | let magnitudeBuffer = self.magnitude.serializeToBuffer() 127 | 128 | // Similar to BigUInt, a value of 0 should return an empty buffer 129 | guard magnitudeBuffer.count > 0 else { return magnitudeBuffer } 130 | 131 | // Create a new buffer for the signed BigInt value 132 | let newBuffer = UnsafeMutableRawBufferPointer.allocate(byteCount: magnitudeBuffer.count + 1, alignment: 8) 133 | let magnitudeSection = UnsafeMutableRawBufferPointer(rebasing: newBuffer[1...]) 134 | magnitudeSection.copyBytes(from: magnitudeBuffer) 135 | magnitudeBuffer.deallocate() 136 | 137 | // The first byte should be 0 for a positive value, or 1 for a negative value 138 | // i.e., the sign bit is the LSB 139 | newBuffer[0] = self.sign == .plus ? 0 : 1 140 | 141 | return UnsafeRawBufferPointer(start: newBuffer.baseAddress, count: newBuffer.count) 142 | } 143 | 144 | #if canImport(Foundation) 145 | /// Initializes an integer from the bits stored inside a piece of `Data`. 146 | /// The data is assumed to be in network (big-endian) byte order with a first 147 | /// byte to represent the sign (0 for positive, 1 for negative) 148 | public init(_ data: Data) { 149 | self = data.withUnsafeBytes({ buffer in 150 | BigInt(buffer) 151 | }) 152 | } 153 | 154 | /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative) 155 | public func serialize() -> Data { 156 | let buffer = serializeToBuffer() 157 | defer { buffer.deallocate() } 158 | guard 159 | let pointer = buffer.baseAddress.map(UnsafeMutableRawPointer.init(mutating:)) 160 | else { return Data() } 161 | 162 | return Data(bytes: pointer, count: buffer.count) 163 | } 164 | #endif 165 | } 166 | -------------------------------------------------------------------------------- /Sources/Exponentiation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Exponentiation.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | //MARK: Exponentiation 11 | 12 | /// Returns this integer raised to the power `exponent`. 13 | /// 14 | /// This function calculates the result by [successively squaring the base while halving the exponent][expsqr]. 15 | /// 16 | /// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring 17 | /// 18 | /// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is 19 | /// a simple integer value. If you want to calculate big exponents, you'll probably need to use 20 | /// the modulo arithmetic variant. 21 | /// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.) 22 | /// - SeeAlso: `BigUInt.power(_:, modulus:)` 23 | /// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too. 24 | public func power(_ exponent: Int) -> BigUInt { 25 | if exponent == 0 { return 1 } 26 | if exponent == 1 { return self } 27 | if exponent < 0 { 28 | precondition(!self.isZero) 29 | return self == 1 ? 1 : 0 30 | } 31 | if self <= 1 { return self } 32 | var result = BigUInt(1) 33 | var b = self 34 | var e = exponent 35 | while e > 0 { 36 | if e & 1 == 1 { 37 | result *= b 38 | } 39 | e >>= 1 40 | b *= b 41 | } 42 | return result 43 | } 44 | 45 | /// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`. 46 | /// 47 | /// Uses the [right-to-left binary method][rtlb]. 48 | /// 49 | /// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method 50 | /// 51 | /// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch 52 | public func power(_ exponent: BigUInt, modulus: BigUInt) -> BigUInt { 53 | precondition(!modulus.isZero) 54 | if modulus == (1 as BigUInt) { return 0 } 55 | let shift = modulus.leadingZeroBitCount 56 | let normalizedModulus = modulus << shift 57 | var result = BigUInt(1) 58 | var b = self 59 | b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) 60 | for var e in exponent.words { 61 | for _ in 0 ..< Word.bitWidth { 62 | if e & 1 == 1 { 63 | result *= b 64 | result.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) 65 | } 66 | e >>= 1 67 | b *= b 68 | b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) 69 | } 70 | } 71 | return result 72 | } 73 | } 74 | 75 | extension BigInt { 76 | /// Returns this integer raised to the power `exponent`. 77 | /// 78 | /// This function calculates the result by [successively squaring the base while halving the exponent][expsqr]. 79 | /// 80 | /// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring 81 | /// 82 | /// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is 83 | /// a simple integer value. If you want to calculate big exponents, you'll probably need to use 84 | /// the modulo arithmetic variant. 85 | /// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.) 86 | /// - SeeAlso: `BigUInt.power(_:, modulus:)` 87 | /// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too. 88 | public func power(_ exponent: Int) -> BigInt { 89 | return BigInt(sign: self.sign == .minus && exponent & 1 != 0 ? .minus : .plus, 90 | magnitude: self.magnitude.power(exponent)) 91 | } 92 | 93 | /// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`. 94 | /// 95 | /// Uses the [right-to-left binary method][rtlb]. 96 | /// 97 | /// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method 98 | /// 99 | /// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch 100 | public func power(_ exponent: BigInt, modulus: BigInt) -> BigInt { 101 | precondition(!modulus.isZero) 102 | if modulus.magnitude == 1 { return 0 } 103 | if exponent.isZero { return 1 } 104 | if exponent == 1 { return self.modulus(modulus) } 105 | if exponent < 0 { 106 | precondition(!self.isZero) 107 | guard magnitude == 1 else { return 0 } 108 | guard sign == .minus else { return 1 } 109 | guard exponent.magnitude[0] & 1 != 0 else { return 1 } 110 | return BigInt(modulus.magnitude - 1) 111 | } 112 | let power = self.magnitude.power(exponent.magnitude, 113 | modulus: modulus.magnitude) 114 | if self.sign == .plus || exponent.magnitude[0] & 1 == 0 || power.isZero { 115 | return BigInt(power) 116 | } 117 | return BigInt(modulus.magnitude - power) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Sources/Floating Point Conversion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Floating Point Conversion.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-08-11. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | #if canImport(Foundation) 10 | import Foundation 11 | #endif 12 | 13 | extension BigUInt { 14 | public init?(exactly source: T) { 15 | guard source.isFinite else { return nil } 16 | guard !source.isZero else { self = 0; return } 17 | guard source.sign == .plus else { return nil } 18 | let value = source.rounded(.towardZero) 19 | guard value == source else { return nil } 20 | assert(value.floatingPointClass == .positiveNormal) 21 | assert(value.exponent >= 0) 22 | let significand = value.significandBitPattern 23 | self = (BigUInt(1) << value.exponent) + BigUInt(significand) >> (T.significandBitCount - Int(value.exponent)) 24 | } 25 | 26 | public init(_ source: T) { 27 | self.init(exactly: source.rounded(.towardZero))! 28 | } 29 | 30 | #if canImport(Foundation) 31 | public init?(exactly source: Decimal) { 32 | guard source.exponent >= 0 else { return nil } 33 | self.init(commonDecimal: source) 34 | } 35 | 36 | public init?(truncating source: Decimal) { 37 | self.init(commonDecimal: source) 38 | } 39 | 40 | private init?(commonDecimal source: Decimal) { 41 | var integer = source 42 | if source.exponent < 0 { 43 | var source = source 44 | NSDecimalRound(&integer, &source, 0, .down) 45 | } 46 | 47 | guard !integer.isZero else { self = 0; return } 48 | guard integer.isFinite else { return nil } 49 | guard integer.sign == .plus else { return nil } 50 | assert(integer.floatingPointClass == .positiveNormal) 51 | 52 | #if os(Linux) || os(Android) || os(Windows) 53 | // `Decimal._mantissa` has an internal access level on linux, and it might get 54 | // deprecated in the future, so keeping the string implementation around for now. 55 | let significand = BigUInt("\(integer.significand)")! 56 | #else 57 | let significand = { 58 | var start = BigUInt(0) 59 | for (place, value) in integer.significand.mantissaParts.enumerated() { 60 | guard value > 0 else { continue } 61 | start += (1 << (place * 16)) * BigUInt(value) 62 | } 63 | return start 64 | }() 65 | #endif 66 | let exponent = BigUInt(10).power(integer.exponent) 67 | 68 | self = significand * exponent 69 | } 70 | #endif 71 | } 72 | 73 | extension BigInt { 74 | public init?(exactly source: T) { 75 | guard let magnitude = BigUInt(exactly: source.magnitude) else { return nil } 76 | let sign = BigInt.Sign(source.sign) 77 | self.init(sign: sign, magnitude: magnitude) 78 | } 79 | 80 | public init(_ source: T) { 81 | self.init(exactly: source.rounded(.towardZero))! 82 | } 83 | 84 | #if canImport(Foundation) 85 | public init?(exactly source: Decimal) { 86 | guard let magnitude = BigUInt(exactly: source.magnitude) else { return nil } 87 | let sign = BigInt.Sign(source.sign) 88 | self.init(sign: sign, magnitude: magnitude) 89 | } 90 | 91 | public init?(truncating source: Decimal) { 92 | guard let magnitude = BigUInt(truncating: source.magnitude) else { return nil } 93 | let sign = BigInt.Sign(source.sign) 94 | self.init(sign: sign, magnitude: magnitude) 95 | } 96 | #endif 97 | } 98 | 99 | extension BinaryFloatingPoint where RawExponent: FixedWidthInteger, RawSignificand: FixedWidthInteger { 100 | public init(_ value: BigInt) { 101 | guard !value.isZero else { self = 0; return } 102 | let v = value.magnitude 103 | let bitWidth = v.bitWidth 104 | var exponent = bitWidth - 1 105 | let shift = bitWidth - Self.significandBitCount - 1 106 | var significand = value.magnitude >> (shift - 1) 107 | if significand[0] & 3 == 3 { // Handle rounding 108 | significand >>= 1 109 | significand += 1 110 | if significand.trailingZeroBitCount >= Self.significandBitCount { 111 | exponent += 1 112 | } 113 | } 114 | else { 115 | significand >>= 1 116 | } 117 | let bias = 1 << (Self.exponentBitCount - 1) - 1 118 | guard exponent <= bias else { self = Self.infinity; return } 119 | significand &= 1 << Self.significandBitCount - 1 120 | self = Self.init(sign: value.sign == .plus ? .plus : .minus, 121 | exponentBitPattern: RawExponent(bias + exponent), 122 | significandBitPattern: RawSignificand(significand)) 123 | } 124 | 125 | public init(_ value: BigUInt) { 126 | self.init(BigInt(sign: .plus, magnitude: value)) 127 | } 128 | } 129 | 130 | extension BigInt.Sign { 131 | public init(_ sign: FloatingPointSign) { 132 | switch sign { 133 | case .plus: 134 | self = .plus 135 | case .minus: 136 | self = .minus 137 | } 138 | } 139 | } 140 | 141 | #if canImport(Foundation) 142 | public extension Decimal { 143 | init(_ value: BigUInt) { 144 | guard 145 | value < BigUInt(exactly: Decimal.greatestFiniteMagnitude)! 146 | else { 147 | self = .greatestFiniteMagnitude 148 | return 149 | } 150 | guard !value.isZero else { self = 0; return } 151 | 152 | self.init(string: "\(value)")! 153 | } 154 | 155 | init(_ value: BigInt) { 156 | if value >= 0 { 157 | self.init(BigUInt(value)) 158 | } else { 159 | self.init(value.magnitude) 160 | self *= -1 161 | } 162 | } 163 | } 164 | #endif 165 | 166 | #if canImport(Foundation) && !(os(Linux) || os(Android) || os(Windows)) 167 | private extension Decimal { 168 | var mantissaParts: [UInt16] { 169 | [ 170 | _mantissa.0, 171 | _mantissa.1, 172 | _mantissa.2, 173 | _mantissa.3, 174 | _mantissa.4, 175 | _mantissa.5, 176 | _mantissa.6, 177 | _mantissa.7, 178 | ] 179 | } 180 | } 181 | #endif 182 | -------------------------------------------------------------------------------- /Sources/GCD.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GCD.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | //MARK: Greatest Common Divisor 11 | 12 | /// Returns the greatest common divisor of `self` and `b`. 13 | /// 14 | /// - Complexity: O(count^2) where count = max(self.count, b.count) 15 | public func greatestCommonDivisor(with b: BigUInt) -> BigUInt { 16 | // This is Stein's algorithm: https://en.wikipedia.org/wiki/Binary_GCD_algorithm 17 | if self.isZero { return b } 18 | if b.isZero { return self } 19 | 20 | let az = self.trailingZeroBitCount 21 | let bz = b.trailingZeroBitCount 22 | let twos = Swift.min(az, bz) 23 | 24 | var (x, y) = (self >> az, b >> bz) 25 | if x < y { swap(&x, &y) } 26 | 27 | while !x.isZero { 28 | x >>= x.trailingZeroBitCount 29 | if x < y { swap(&x, &y) } 30 | x -= y 31 | } 32 | return y << twos 33 | } 34 | 35 | /// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse], 36 | /// or `nil` if there is no such number. 37 | /// 38 | /// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers 39 | /// 40 | /// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`. 41 | /// - Requires: modulus > 1 42 | /// - Complexity: O(count^3) 43 | public func inverse(_ modulus: BigUInt) -> BigUInt? { 44 | precondition(modulus > 1) 45 | var t1 = BigInt(0) 46 | var t2 = BigInt(1) 47 | var r1 = modulus 48 | var r2 = self 49 | while !r2.isZero { 50 | let quotient = r1 / r2 51 | (t1, t2) = (t2, t1 - BigInt(quotient) * t2) 52 | (r1, r2) = (r2, r1 - quotient * r2) 53 | } 54 | if r1 > 1 { return nil } 55 | if t1.sign == .minus { return modulus - t1.magnitude } 56 | return t1.magnitude 57 | } 58 | } 59 | 60 | extension BigInt { 61 | /// Returns the greatest common divisor of `a` and `b`. 62 | /// 63 | /// - Complexity: O(count^2) where count = max(a.count, b.count) 64 | public func greatestCommonDivisor(with b: BigInt) -> BigInt { 65 | return BigInt(self.magnitude.greatestCommonDivisor(with: b.magnitude)) 66 | } 67 | 68 | /// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse], 69 | /// or `nil` if there is no such number. 70 | /// 71 | /// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers 72 | /// 73 | /// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`. 74 | /// - Requires: modulus.magnitude > 1 75 | /// - Complexity: O(count^3) 76 | public func inverse(_ modulus: BigInt) -> BigInt? { 77 | guard let inv = self.magnitude.inverse(modulus.magnitude) else { return nil } 78 | return BigInt(self.sign == .plus || inv.isZero ? inv : modulus.magnitude - inv) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Sources/Hashable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Hashable.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt: Hashable { 10 | //MARK: Hashing 11 | 12 | /// Append this `BigUInt` to the specified hasher. 13 | public func hash(into hasher: inout Hasher) { 14 | for word in self.words { 15 | hasher.combine(word) 16 | } 17 | } 18 | } 19 | 20 | extension BigInt: Hashable { 21 | /// Append this `BigInt` to the specified hasher. 22 | public func hash(into hasher: inout Hasher) { 23 | hasher.combine(sign) 24 | hasher.combine(magnitude) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Integer Conversion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Integer Conversion.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-08-11. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | public init?(exactly source: T) { 11 | guard source >= (0 as T) else { return nil } 12 | if source.bitWidth <= 2 * Word.bitWidth { 13 | var it = source.words.makeIterator() 14 | self.init(low: it.next() ?? 0, high: it.next() ?? 0) 15 | precondition(it.next() == nil, "Length of BinaryInteger.words is greater than its bitWidth") 16 | } 17 | else { 18 | self.init(words: source.words) 19 | } 20 | } 21 | 22 | public init(_ source: T) { 23 | precondition(source >= (0 as T), "BigUInt cannot represent negative values") 24 | self.init(exactly: source)! 25 | } 26 | 27 | public init(truncatingIfNeeded source: T) { 28 | self.init(words: source.words) 29 | } 30 | 31 | public init(clamping source: T) { 32 | if source <= (0 as T) { 33 | self.init() 34 | } 35 | else { 36 | self.init(words: source.words) 37 | } 38 | } 39 | } 40 | 41 | extension BigInt { 42 | public init() { 43 | self.init(sign: .plus, magnitude: 0) 44 | } 45 | 46 | /// Initializes a new signed big integer with the same value as the specified unsigned big integer. 47 | public init(_ integer: BigUInt) { 48 | self.magnitude = integer 49 | self.sign = .plus 50 | } 51 | 52 | public init(_ source: T) where T : BinaryInteger { 53 | if source >= (0 as T) { 54 | self.init(sign: .plus, magnitude: BigUInt(source)) 55 | } 56 | else { 57 | var words = Array(source.words) 58 | words.twosComplement() 59 | self.init(sign: .minus, magnitude: BigUInt(words: words)) 60 | } 61 | } 62 | 63 | public init?(exactly source: T) where T : BinaryInteger { 64 | self.init(source) 65 | } 66 | 67 | public init(clamping source: T) where T : BinaryInteger { 68 | self.init(source) 69 | } 70 | 71 | public init(truncatingIfNeeded source: T) where T : BinaryInteger { 72 | self.init(source) 73 | } 74 | } 75 | 76 | extension BigUInt: ExpressibleByIntegerLiteral { 77 | /// Initialize a new big integer from an integer literal. 78 | public init(integerLiteral value: UInt64) { 79 | self.init(value) 80 | } 81 | } 82 | 83 | extension BigInt: ExpressibleByIntegerLiteral { 84 | /// Initialize a new big integer from an integer literal. 85 | public init(integerLiteral value: Int64) { 86 | self.init(value) 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /Sources/Multiplication.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Multiplication.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | 11 | //MARK: Multiplication 12 | 13 | /// Multiply this big integer by a single word, and store the result in place of the original big integer. 14 | /// 15 | /// - Complexity: O(count) 16 | public mutating func multiply(byWord y: Word) { 17 | guard y != 0 else { self = 0; return } 18 | guard y != 1 else { return } 19 | var carry: Word = 0 20 | let c = self.count 21 | for i in 0 ..< c { 22 | let (h, l) = self[i].multipliedFullWidth(by: y) 23 | let (low, o) = l.addingReportingOverflow(carry) 24 | self[i] = low 25 | carry = (o ? h + 1 : h) 26 | } 27 | self[c] = carry 28 | } 29 | 30 | /// Multiply this big integer by a single Word, and return the result. 31 | /// 32 | /// - Complexity: O(count) 33 | public func multiplied(byWord y: Word) -> BigUInt { 34 | var r = self 35 | r.multiply(byWord: y) 36 | return r 37 | } 38 | 39 | /// Multiply `x` by `y`, and add the result to this integer, optionally shifted `shift` words to the left. 40 | /// 41 | /// - Note: This is the fused multiply/shift/add operation; it is more efficient than doing the components 42 | /// individually. (The fused operation doesn't need to allocate space for temporary big integers.) 43 | /// `self` is set to `self + (x * y) << (shift * 2^Word.bitWidth)` 44 | /// - Complexity: O(count) 45 | public mutating func multiplyAndAdd(_ x: BigUInt, _ y: Word, shiftedBy shift: Int = 0) { 46 | precondition(shift >= 0) 47 | guard y != 0 && x.count > 0 else { return } 48 | guard y != 1 else { self.add(x, shiftedBy: shift); return } 49 | var mulCarry: Word = 0 50 | var addCarry = false 51 | let xc = x.count 52 | var xi = 0 53 | while xi < xc || addCarry || mulCarry > 0 { 54 | let (h, l) = x[xi].multipliedFullWidth(by: y) 55 | let (low, o) = l.addingReportingOverflow(mulCarry) 56 | mulCarry = (o ? h + 1 : h) 57 | 58 | let ai = shift + xi 59 | let (sum1, so1) = self[ai].addingReportingOverflow(low) 60 | if addCarry { 61 | let (sum2, so2) = sum1.addingReportingOverflow(1) 62 | self[ai] = sum2 63 | addCarry = so1 || so2 64 | } 65 | else { 66 | self[ai] = sum1 67 | addCarry = so1 68 | } 69 | xi += 1 70 | } 71 | } 72 | 73 | /// Multiply this integer by `y` and return the result. 74 | /// 75 | /// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than 76 | /// `BigUInt.directMultiplicationLimit` words. 77 | /// - Complexity: O(n^log2(3)) 78 | public func multiplied(by y: BigUInt) -> BigUInt { 79 | // This method is mostly defined for symmetry with the rest of the arithmetic operations. 80 | return self * y 81 | } 82 | 83 | /// Multiplication switches to an asymptotically better recursive algorithm when arguments have more words than this limit. 84 | public static let directMultiplicationLimit: Int = 1024 85 | 86 | /// Multiply `a` by `b` and return the result. 87 | /// 88 | /// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than 89 | /// `BigUInt.directMultiplicationLimit` words. 90 | /// - Complexity: O(n^log2(3)) 91 | public static func *(x: BigUInt, y: BigUInt) -> BigUInt { 92 | let xc = x.count 93 | let yc = y.count 94 | if xc == 0 { return BigUInt() } 95 | if yc == 0 { return BigUInt() } 96 | if yc == 1 { return x.multiplied(byWord: y[0]) } 97 | if xc == 1 { return y.multiplied(byWord: x[0]) } 98 | 99 | if Swift.min(xc, yc) <= BigUInt.directMultiplicationLimit { 100 | // Long multiplication. 101 | let left = (xc < yc ? y : x) 102 | let right = (xc < yc ? x : y) 103 | var result = BigUInt() 104 | for i in (0 ..< right.count).reversed() { 105 | result.multiplyAndAdd(left, right[i], shiftedBy: i) 106 | } 107 | return result 108 | } 109 | 110 | if yc < xc { 111 | let (xh, xl) = x.split 112 | var r = xl * y 113 | r.add(xh * y, shiftedBy: x.middleIndex) 114 | return r 115 | } 116 | else if xc < yc { 117 | let (yh, yl) = y.split 118 | var r = yl * x 119 | r.add(yh * x, shiftedBy: y.middleIndex) 120 | return r 121 | } 122 | 123 | let shift = x.middleIndex 124 | 125 | // Karatsuba multiplication: 126 | // x * y = * = (ignoring carry) 127 | let (a, b) = x.split 128 | let (c, d) = y.split 129 | 130 | let high = a * c 131 | let low = b * d 132 | let xp = a >= b 133 | let yp = c >= d 134 | let xm = (xp ? a - b : b - a) 135 | let ym = (yp ? c - d : d - c) 136 | let m = xm * ym 137 | 138 | var r = low 139 | r.add(high, shiftedBy: 2 * shift) 140 | r.add(low, shiftedBy: shift) 141 | r.add(high, shiftedBy: shift) 142 | if xp == yp { 143 | r.subtract(m, shiftedBy: shift) 144 | } 145 | else { 146 | r.add(m, shiftedBy: shift) 147 | } 148 | return r 149 | } 150 | 151 | /// Multiply `a` by `b` and store the result in `a`. 152 | public static func *=(a: inout BigUInt, b: BigUInt) { 153 | a = a * b 154 | } 155 | } 156 | 157 | extension BigInt { 158 | /// Multiply `a` with `b` and return the result. 159 | public static func *(a: BigInt, b: BigInt) -> BigInt { 160 | return BigInt(sign: a.sign == b.sign ? .plus : .minus, magnitude: a.magnitude * b.magnitude) 161 | } 162 | 163 | /// Multiply `a` with `b` in place. 164 | public static func *=(a: inout BigInt, b: BigInt) { a = a * b } 165 | } 166 | -------------------------------------------------------------------------------- /Sources/Prime Test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Prime Test.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-04. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | /// The first several [prime numbers][primes]. 10 | /// 11 | /// [primes]: https://oeis.org/A000040 12 | let primes: [BigUInt.Word] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41] 13 | 14 | /// The ith element in this sequence is the smallest composite number that passes the strong probable prime test 15 | /// for all of the first (i+1) primes. 16 | /// 17 | /// This is sequence [A014233](http://oeis.org/A014233) on the [Online Encyclopaedia of Integer Sequences](http://oeis.org). 18 | let pseudoPrimes: [BigUInt] = [ 19 | /* 2 */ 2_047, 20 | /* 3 */ 1_373_653, 21 | /* 5 */ 25_326_001, 22 | /* 7 */ 3_215_031_751, 23 | /* 11 */ 2_152_302_898_747, 24 | /* 13 */ 3_474_749_660_383, 25 | /* 17 */ 341_550_071_728_321, 26 | /* 19 */ 341_550_071_728_321, 27 | /* 23 */ 3_825_123_056_546_413_051, 28 | /* 29 */ 3_825_123_056_546_413_051, 29 | /* 31 */ 3_825_123_056_546_413_051, 30 | /* 37 */ "318665857834031151167461", 31 | /* 41 */ "3317044064679887385961981", 32 | ] 33 | 34 | extension BigUInt { 35 | //MARK: Primality Testing 36 | 37 | /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base. 38 | /// 39 | /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime 40 | public func isStrongProbablePrime(_ base: BigUInt) -> Bool { 41 | precondition(base > (1 as BigUInt)) 42 | precondition(self > (0 as BigUInt)) 43 | let dec = self - 1 44 | 45 | let r = dec.trailingZeroBitCount 46 | let d = dec >> r 47 | 48 | var test = base.power(d, modulus: self) 49 | if test == 1 || test == dec { return true } 50 | 51 | if r > 0 { 52 | let shift = self.leadingZeroBitCount 53 | let normalized = self << shift 54 | for _ in 1 ..< r { 55 | test *= test 56 | test.formRemainder(dividingBy: normalized, normalizedBy: shift) 57 | if test == 1 { 58 | return false 59 | } 60 | if test == dec { return true } 61 | } 62 | } 63 | return false 64 | } 65 | 66 | /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime. 67 | /// 68 | /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations, 69 | /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default, 70 | /// but you may specify your own choice. 71 | /// 72 | /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before 73 | /// diving into (slower) Miller-Rabin testing. 74 | /// 75 | /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to 76 | /// return a correct result. 77 | /// 78 | /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test 79 | public func isPrime(rounds: Int = 10) -> Bool { 80 | if count <= 1 && self[0] < 2 { return false } 81 | if count == 1 && self[0] < 4 { return true } 82 | 83 | // Even numbers above 2 aren't prime. 84 | if self[0] & 1 == 0 { return false } 85 | 86 | // Quickly check for small primes. 87 | for i in 1 ..< primes.count { 88 | let p = primes[i] 89 | if self.count == 1 && self[0] == p { 90 | return true 91 | } 92 | if self.quotientAndRemainder(dividingByWord: p).remainder == 0 { 93 | return false 94 | } 95 | } 96 | 97 | /// Give an exact answer when we can. 98 | if self < pseudoPrimes.last! { 99 | for i in 0 ..< pseudoPrimes.count { 100 | guard isStrongProbablePrime(BigUInt(primes[i])) else { 101 | break 102 | } 103 | if self < pseudoPrimes[i] { 104 | // `self` is below the lowest pseudoprime corresponding to the prime bases we tested. It's a prime! 105 | return true 106 | } 107 | } 108 | return false 109 | } 110 | 111 | /// Otherwise do as many rounds of random SPPT as required. 112 | for _ in 0 ..< rounds { 113 | let random = BigUInt.randomInteger(lessThan: self - 2) + 2 114 | guard isStrongProbablePrime(random) else { 115 | return false 116 | } 117 | } 118 | 119 | // Well, it smells primey to me. 120 | return true 121 | } 122 | } 123 | 124 | extension BigInt { 125 | //MARK: Primality Testing 126 | 127 | /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base. 128 | /// 129 | /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime 130 | public func isStrongProbablePrime(_ base: BigInt) -> Bool { 131 | precondition(base.sign == .plus) 132 | if self.sign == .minus { return false } 133 | return self.magnitude.isStrongProbablePrime(base.magnitude) 134 | } 135 | 136 | /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime. 137 | /// 138 | /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations, 139 | /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default, 140 | /// but you may specify your own choice. 141 | /// 142 | /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before 143 | /// diving into (slower) Miller-Rabin testing. 144 | /// 145 | /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to 146 | /// return a correct result. 147 | /// 148 | /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test 149 | public func isPrime(rounds: Int = 10) -> Bool { 150 | if self.sign == .minus { return false } 151 | return self.magnitude.isPrime(rounds: rounds) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Sources/Random.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Random.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-04. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | /// Create a big unsigned integer consisting of `width` uniformly distributed random bits. 11 | /// 12 | /// - Parameter width: The maximum number of one bits in the result. 13 | /// - Parameter generator: The source of randomness. 14 | /// - Returns: A big unsigned integer less than `1 << width`. 15 | public static func randomInteger(withMaximumWidth width: Int, using generator: inout RNG) -> BigUInt { 16 | var result = BigUInt.zero 17 | var bitsLeft = width 18 | var i = 0 19 | let wordsNeeded = (width + Word.bitWidth - 1) / Word.bitWidth 20 | if wordsNeeded > 2 { 21 | result.reserveCapacity(wordsNeeded) 22 | } 23 | while bitsLeft >= Word.bitWidth { 24 | result[i] = generator.next() 25 | i += 1 26 | bitsLeft -= Word.bitWidth 27 | } 28 | if bitsLeft > 0 { 29 | let mask: Word = (1 << bitsLeft) - 1 30 | result[i] = (generator.next() as Word) & mask 31 | } 32 | return result 33 | } 34 | 35 | /// Create a big unsigned integer consisting of `width` uniformly distributed random bits. 36 | /// 37 | /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. 38 | /// 39 | /// - Parameter width: The maximum number of one bits in the result. 40 | /// - Returns: A big unsigned integer less than `1 << width`. 41 | public static func randomInteger(withMaximumWidth width: Int) -> BigUInt { 42 | var rng = SystemRandomNumberGenerator() 43 | return randomInteger(withMaximumWidth: width, using: &rng) 44 | } 45 | 46 | /// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit. 47 | /// 48 | /// - Note: If `width` is zero, the result is zero. 49 | /// 50 | /// - Parameter width: The number of bits required to represent the answer. 51 | /// - Parameter generator: The source of randomness. 52 | /// - Returns: A random big unsigned integer whose width is `width`. 53 | public static func randomInteger(withExactWidth width: Int, using generator: inout RNG) -> BigUInt { 54 | // width == 0 -> return 0 because there is no room for a one bit. 55 | // width == 1 -> return 1 because there is no room for any random bits. 56 | guard width > 1 else { return BigUInt(width) } 57 | var result = randomInteger(withMaximumWidth: width - 1, using: &generator) 58 | result[(width - 1) / Word.bitWidth] |= 1 << Word((width - 1) % Word.bitWidth) 59 | return result 60 | } 61 | 62 | /// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit. 63 | /// 64 | /// - Note: If `width` is zero, the result is zero. 65 | /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. 66 | /// 67 | /// - Returns: A random big unsigned integer whose width is `width`. 68 | public static func randomInteger(withExactWidth width: Int) -> BigUInt { 69 | var rng = SystemRandomNumberGenerator() 70 | return randomInteger(withExactWidth: width, using: &rng) 71 | } 72 | 73 | /// Create a uniformly distributed random unsigned integer that's less than the specified limit. 74 | /// 75 | /// - Precondition: `limit > 0`. 76 | /// 77 | /// - Parameter limit: The upper bound on the result. 78 | /// - Parameter generator: The source of randomness. 79 | /// - Returns: A random big unsigned integer that is less than `limit`. 80 | public static func randomInteger(lessThan limit: BigUInt, using generator: inout RNG) -> BigUInt { 81 | precondition(limit > 0, "\(#function): 0 is not a valid limit") 82 | let width = limit.bitWidth 83 | var random = randomInteger(withMaximumWidth: width, using: &generator) 84 | while random >= limit { 85 | random = randomInteger(withMaximumWidth: width, using: &generator) 86 | } 87 | return random 88 | } 89 | 90 | /// Create a uniformly distributed random unsigned integer that's less than the specified limit. 91 | /// 92 | /// - Precondition: `limit > 0`. 93 | /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. 94 | /// 95 | /// - Parameter limit: The upper bound on the result. 96 | /// - Returns: A random big unsigned integer that is less than `limit`. 97 | public static func randomInteger(lessThan limit: BigUInt) -> BigUInt { 98 | var rng = SystemRandomNumberGenerator() 99 | return randomInteger(lessThan: limit, using: &rng) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Sources/Shifts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Shifts.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | 11 | //MARK: Shift Operators 12 | 13 | internal func shiftedLeft(by amount: Word) -> BigUInt { 14 | guard amount > 0 else { return self } 15 | 16 | let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) 17 | let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) 18 | let down = Word(Word.bitWidth) - up 19 | 20 | var result = BigUInt() 21 | if up > 0 { 22 | var i = 0 23 | var lowbits: Word = 0 24 | while i < self.count || lowbits > 0 { 25 | let word = self[i] 26 | result[i + ext] = word << up | lowbits 27 | lowbits = word >> down 28 | i += 1 29 | } 30 | } 31 | else { 32 | for i in 0 ..< self.count { 33 | result[i + ext] = self[i] 34 | } 35 | } 36 | return result 37 | } 38 | 39 | internal mutating func shiftLeft(by amount: Word) { 40 | guard amount > 0 else { return } 41 | 42 | let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) 43 | let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) 44 | let down = Word(Word.bitWidth) - up 45 | 46 | if up > 0 { 47 | var i = 0 48 | var lowbits: Word = 0 49 | while i < self.count || lowbits > 0 { 50 | let word = self[i] 51 | self[i] = word << up | lowbits 52 | lowbits = word >> down 53 | i += 1 54 | } 55 | } 56 | if ext > 0 && self.count > 0 { 57 | self.shiftLeft(byWords: ext) 58 | } 59 | } 60 | 61 | internal func shiftedRight(by amount: Word) -> BigUInt { 62 | guard amount > 0 else { return self } 63 | guard amount < self.bitWidth else { return 0 } 64 | 65 | let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) 66 | let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) 67 | let up = Word(Word.bitWidth) - down 68 | 69 | var result = BigUInt() 70 | if down > 0 { 71 | var highbits: Word = 0 72 | for i in (ext ..< self.count).reversed() { 73 | let word = self[i] 74 | result[i - ext] = highbits | word >> down 75 | highbits = word << up 76 | } 77 | } 78 | else { 79 | for i in (ext ..< self.count).reversed() { 80 | result[i - ext] = self[i] 81 | } 82 | } 83 | return result 84 | } 85 | 86 | internal mutating func shiftRight(by amount: Word) { 87 | guard amount > 0 else { return } 88 | guard amount < self.bitWidth else { self.clear(); return } 89 | 90 | let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) 91 | let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) 92 | let up = Word(Word.bitWidth) - down 93 | 94 | if ext > 0 { 95 | self.shiftRight(byWords: ext) 96 | } 97 | if down > 0 { 98 | var i = self.count - 1 99 | var highbits: Word = 0 100 | while i >= 0 { 101 | let word = self[i] 102 | self[i] = highbits | word >> down 103 | highbits = word << up 104 | i -= 1 105 | } 106 | } 107 | } 108 | 109 | public static func >>=(lhs: inout BigUInt, rhs: Other) { 110 | if rhs < (0 as Other) { 111 | lhs <<= (0 - rhs) 112 | } 113 | else if rhs >= lhs.bitWidth { 114 | lhs.clear() 115 | } 116 | else { 117 | lhs.shiftRight(by: UInt(rhs)) 118 | } 119 | } 120 | 121 | public static func <<=(lhs: inout BigUInt, rhs: Other) { 122 | if rhs < (0 as Other) { 123 | lhs >>= (0 - rhs) 124 | return 125 | } 126 | lhs.shiftLeft(by: Word(exactly: rhs)!) 127 | } 128 | 129 | public static func >>(lhs: BigUInt, rhs: Other) -> BigUInt { 130 | if rhs < (0 as Other) { 131 | return lhs << (0 - rhs) 132 | } 133 | if rhs > Word.max { 134 | return 0 135 | } 136 | return lhs.shiftedRight(by: UInt(rhs)) 137 | } 138 | 139 | public static func <<(lhs: BigUInt, rhs: Other) -> BigUInt { 140 | if rhs < (0 as Other) { 141 | return lhs >> (0 - rhs) 142 | } 143 | return lhs.shiftedLeft(by: Word(exactly: rhs)!) 144 | } 145 | } 146 | 147 | extension BigInt { 148 | func shiftedLeft(by amount: Word) -> BigInt { 149 | return BigInt(sign: self.sign, magnitude: self.magnitude.shiftedLeft(by: amount)) 150 | } 151 | 152 | mutating func shiftLeft(by amount: Word) { 153 | self.magnitude.shiftLeft(by: amount) 154 | } 155 | 156 | func shiftedRight(by amount: Word) -> BigInt { 157 | let m = self.magnitude.shiftedRight(by: amount) 158 | return BigInt(sign: self.sign, magnitude: self.sign == .minus && m.isZero ? 1 : m) 159 | } 160 | 161 | mutating func shiftRight(by amount: Word) { 162 | magnitude.shiftRight(by: amount) 163 | if sign == .minus, magnitude.isZero { 164 | magnitude.load(1) 165 | } 166 | } 167 | 168 | public static func &<<(left: BigInt, right: BigInt) -> BigInt { 169 | return left.shiftedLeft(by: right.words[0]) 170 | } 171 | 172 | public static func &<<=(left: inout BigInt, right: BigInt) { 173 | left.shiftLeft(by: right.words[0]) 174 | } 175 | 176 | public static func &>>(left: BigInt, right: BigInt) -> BigInt { 177 | return left.shiftedRight(by: right.words[0]) 178 | } 179 | 180 | public static func &>>=(left: inout BigInt, right: BigInt) { 181 | left.shiftRight(by: right.words[0]) 182 | } 183 | 184 | public static func <<(lhs: BigInt, rhs: Other) -> BigInt { 185 | guard rhs >= (0 as Other) else { return lhs >> (0 - rhs) } 186 | return lhs.shiftedLeft(by: Word(rhs)) 187 | } 188 | 189 | public static func <<=(lhs: inout BigInt, rhs: Other) { 190 | if rhs < (0 as Other) { 191 | lhs >>= (0 - rhs) 192 | } 193 | else { 194 | lhs.shiftLeft(by: Word(rhs)) 195 | } 196 | } 197 | 198 | public static func >>(lhs: BigInt, rhs: Other) -> BigInt { 199 | guard rhs >= (0 as Other) else { return lhs << (0 - rhs) } 200 | return lhs.shiftedRight(by: Word(rhs)) 201 | } 202 | 203 | public static func >>=(lhs: inout BigInt, rhs: Other) { 204 | if rhs < (0 as Other) { 205 | lhs <<= (0 - rhs) 206 | } 207 | else { 208 | lhs.shiftRight(by: Word(rhs)) 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Sources/Square Root.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Square Root.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | //MARK: Square Root 10 | 11 | extension BigUInt { 12 | /// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`. 13 | /// 14 | /// - Returns: floor(sqrt(self)) 15 | public func squareRoot() -> BigUInt { 16 | // This implementation uses Newton's method. 17 | guard !self.isZero else { return BigUInt() } 18 | var x = BigUInt(1) << ((self.bitWidth + 1) / 2) 19 | var y: BigUInt = 0 20 | while true { 21 | y.load(self) 22 | y /= x 23 | y += x 24 | y >>= 1 25 | if x == y || x == y - 1 { break } 26 | x = y 27 | } 28 | return x 29 | } 30 | } 31 | 32 | extension BigInt { 33 | /// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`. 34 | /// 35 | /// - Requires: self >= 0 36 | /// - Returns: floor(sqrt(self)) 37 | public func squareRoot() -> BigInt { 38 | precondition(self.sign == .plus) 39 | return BigInt(sign: .plus, magnitude: self.magnitude.squareRoot()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Strideable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Strideable.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-08-11. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt: Strideable { 10 | /// A type that can represent the distance between two values ofa `BigUInt`. 11 | public typealias Stride = BigInt 12 | 13 | /// Adds `n` to `self` and returns the result. Traps if the result would be less than zero. 14 | public func advanced(by n: BigInt) -> BigUInt { 15 | return n.sign == .minus ? self - n.magnitude : self + n.magnitude 16 | } 17 | 18 | /// Returns the (potentially negative) difference between `self` and `other` as a `BigInt`. Never traps. 19 | public func distance(to other: BigUInt) -> BigInt { 20 | return BigInt(other) - BigInt(self) 21 | } 22 | } 23 | 24 | extension BigInt: Strideable { 25 | public typealias Stride = BigInt 26 | 27 | /// Returns `self + n`. 28 | public func advanced(by n: Stride) -> BigInt { 29 | return self + n 30 | } 31 | 32 | /// Returns `other - self`. 33 | public func distance(to other: BigInt) -> Stride { 34 | return other - self 35 | } 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /Sources/Subtraction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Subtraction.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2016-01-03. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension BigUInt { 10 | //MARK: Subtraction 11 | 12 | /// Subtract `word` from this integer in place, returning a flag indicating if the operation 13 | /// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted. 14 | /// 15 | /// - Note: If the result indicates an overflow, then `self` becomes the two's complement of the absolute difference. 16 | /// - Complexity: O(count) 17 | internal mutating func subtractWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> Bool { 18 | precondition(shift >= 0) 19 | var carry: Word = word 20 | var i = shift 21 | let count = self.count 22 | while carry > 0 && i < count { 23 | let (d, c) = self[i].subtractingReportingOverflow(carry) 24 | self[i] = d 25 | carry = (c ? 1 : 0) 26 | i += 1 27 | } 28 | return carry > 0 29 | } 30 | 31 | /// Subtract `word` from this integer, returning the difference and a flag that is true if the operation 32 | /// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted. 33 | /// 34 | /// - Note: If `overflow` is true, then the returned value is the two's complement of the absolute difference. 35 | /// - Complexity: O(count) 36 | internal func subtractingWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> (partialValue: BigUInt, overflow: Bool) { 37 | var result = self 38 | let overflow = result.subtractWordReportingOverflow(word, shiftedBy: shift) 39 | return (result, overflow) 40 | } 41 | 42 | /// Subtract a digit `d` from this integer in place. 43 | /// `d` is shifted `shift` digits to the left before being subtracted. 44 | /// 45 | /// - Requires: self >= d * 2^shift 46 | /// - Complexity: O(count) 47 | internal mutating func subtractWord(_ word: Word, shiftedBy shift: Int = 0) { 48 | let overflow = subtractWordReportingOverflow(word, shiftedBy: shift) 49 | precondition(!overflow) 50 | } 51 | 52 | /// Subtract a digit `d` from this integer and return the result. 53 | /// `d` is shifted `shift` digits to the left before being subtracted. 54 | /// 55 | /// - Requires: self >= d * 2^shift 56 | /// - Complexity: O(count) 57 | internal func subtractingWord(_ word: Word, shiftedBy shift: Int = 0) -> BigUInt { 58 | var result = self 59 | result.subtractWord(word, shiftedBy: shift) 60 | return result 61 | } 62 | 63 | /// Subtract `other` from this integer in place, and return a flag indicating if the operation caused an 64 | /// arithmetic overflow. `other` is shifted `shift` digits to the left before being subtracted. 65 | /// 66 | /// - Note: If the result indicates an overflow, then `self` becomes the twos' complement of the absolute difference. 67 | /// - Complexity: O(count) 68 | public mutating func subtractReportingOverflow(_ b: BigUInt, shiftedBy shift: Int = 0) -> Bool { 69 | precondition(shift >= 0) 70 | var carry = false 71 | var bi = 0 72 | let bc = b.count 73 | let count = self.count 74 | while bi < bc || (shift + bi < count && carry) { 75 | let ai = shift + bi 76 | let (d, c) = self[ai].subtractingReportingOverflow(b[bi]) 77 | if carry { 78 | let (d2, c2) = d.subtractingReportingOverflow(1) 79 | self[ai] = d2 80 | carry = c || c2 81 | } 82 | else { 83 | self[ai] = d 84 | carry = c 85 | } 86 | bi += 1 87 | } 88 | return carry 89 | } 90 | 91 | /// Subtract `other` from this integer, returning the difference and a flag indicating arithmetic overflow. 92 | /// `other` is shifted `shift` digits to the left before being subtracted. 93 | /// 94 | /// - Note: If `overflow` is true, then the result value is the twos' complement of the absolute value of the difference. 95 | /// - Complexity: O(count) 96 | public func subtractingReportingOverflow(_ other: BigUInt, shiftedBy shift: Int) -> (partialValue: BigUInt, overflow: Bool) { 97 | var result = self 98 | let overflow = result.subtractReportingOverflow(other, shiftedBy: shift) 99 | return (result, overflow) 100 | } 101 | 102 | /// Subtracts `other` from `self`, returning the result and a flag indicating arithmetic overflow. 103 | /// 104 | /// - Note: When the operation overflows, then `partialValue` is the twos' complement of the absolute value of the difference. 105 | /// - Complexity: O(count) 106 | public func subtractingReportingOverflow(_ other: BigUInt) -> (partialValue: BigUInt, overflow: Bool) { 107 | return self.subtractingReportingOverflow(other, shiftedBy: 0) 108 | } 109 | 110 | /// Subtract `other` from this integer in place. 111 | /// `other` is shifted `shift` digits to the left before being subtracted. 112 | /// 113 | /// - Requires: self >= other * 2^shift 114 | /// - Complexity: O(count) 115 | public mutating func subtract(_ other: BigUInt, shiftedBy shift: Int = 0) { 116 | let overflow = subtractReportingOverflow(other, shiftedBy: shift) 117 | precondition(!overflow) 118 | } 119 | 120 | /// Subtract `b` from this integer, and return the difference. 121 | /// `b` is shifted `shift` digits to the left before being subtracted. 122 | /// 123 | /// - Requires: self >= b * 2^shift 124 | /// - Complexity: O(count) 125 | public func subtracting(_ other: BigUInt, shiftedBy shift: Int = 0) -> BigUInt { 126 | var result = self 127 | result.subtract(other, shiftedBy: shift) 128 | return result 129 | } 130 | 131 | /// Decrement this integer by one. 132 | /// 133 | /// - Requires: !isZero 134 | /// - Complexity: O(count) 135 | public mutating func decrement(shiftedBy shift: Int = 0) { 136 | self.subtract(1, shiftedBy: shift) 137 | } 138 | 139 | /// Subtract `b` from `a` and return the result. 140 | /// 141 | /// - Requires: a >= b 142 | /// - Complexity: O(a.count) 143 | public static func -(a: BigUInt, b: BigUInt) -> BigUInt { 144 | return a.subtracting(b) 145 | } 146 | 147 | /// Subtract `b` from `a` and store the result in `a`. 148 | /// 149 | /// - Requires: a >= b 150 | /// - Complexity: O(a.count) 151 | public static func -=(a: inout BigUInt, b: BigUInt) { 152 | a.subtract(b) 153 | } 154 | } 155 | 156 | extension BigInt { 157 | public mutating func negate() { 158 | guard !magnitude.isZero else { return } 159 | self.sign = self.sign == .plus ? .minus : .plus 160 | } 161 | 162 | /// Subtract `b` from `a` and return the result. 163 | public static func -(a: BigInt, b: BigInt) -> BigInt { 164 | return a + -b 165 | } 166 | 167 | /// Subtract `b` from `a` in place. 168 | public static func -=(a: inout BigInt, b: BigInt) { a = a - b } 169 | } 170 | -------------------------------------------------------------------------------- /Sources/Words and Bits.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Words and Bits.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-08-11. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | extension Array where Element == UInt { 10 | mutating func twosComplement() { 11 | var increment = true 12 | for i in 0 ..< self.count { 13 | if increment { 14 | (self[i], increment) = (~self[i]).addingReportingOverflow(1) 15 | } 16 | else { 17 | self[i] = ~self[i] 18 | } 19 | } 20 | } 21 | } 22 | 23 | extension BigUInt { 24 | public subscript(bitAt index: Int) -> Bool { 25 | get { 26 | precondition(index >= 0) 27 | let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth) 28 | return self[i] & (1 << j) != 0 29 | } 30 | set { 31 | precondition(index >= 0) 32 | let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth) 33 | if newValue { 34 | self[i] |= 1 << j 35 | } 36 | else { 37 | self[i] &= ~(1 << j) 38 | } 39 | } 40 | } 41 | } 42 | 43 | extension BigUInt { 44 | /// The minimum number of bits required to represent this integer in binary. 45 | /// 46 | /// - Returns: floor(log2(2 * self + 1)) 47 | /// - Complexity: O(1) 48 | public var bitWidth: Int { 49 | guard count > 0 else { return 0 } 50 | return count * Word.bitWidth - self[count - 1].leadingZeroBitCount 51 | } 52 | 53 | /// The number of leading zero bits in the binary representation of this integer in base `2^(Word.bitWidth)`. 54 | /// This is useful when you need to normalize a `BigUInt` such that the top bit of its most significant word is 1. 55 | /// 56 | /// - Note: 0 is considered to have zero leading zero bits. 57 | /// - Returns: A value in `0...(Word.bitWidth - 1)`. 58 | /// - SeeAlso: width 59 | /// - Complexity: O(1) 60 | public var leadingZeroBitCount: Int { 61 | guard count > 0 else { return 0 } 62 | return self[count - 1].leadingZeroBitCount 63 | } 64 | 65 | /// The number of trailing zero bits in the binary representation of this integer. 66 | /// 67 | /// - Note: 0 is considered to have zero trailing zero bits. 68 | /// - Returns: A value in `0...width`. 69 | /// - Complexity: O(count) 70 | public var trailingZeroBitCount: Int { 71 | guard count > 0 else { return 0 } 72 | let i = self.words.firstIndex { $0 != 0 }! 73 | return i * Word.bitWidth + self[i].trailingZeroBitCount 74 | } 75 | } 76 | 77 | extension BigInt { 78 | public var bitWidth: Int { 79 | guard !magnitude.isZero else { return 0 } 80 | return magnitude.bitWidth + 1 81 | } 82 | 83 | public var trailingZeroBitCount: Int { 84 | // Amazingly, this works fine for negative numbers 85 | return magnitude.trailingZeroBitCount 86 | } 87 | } 88 | 89 | extension BigUInt { 90 | public struct Words: RandomAccessCollection { 91 | private let value: BigUInt 92 | 93 | fileprivate init(_ value: BigUInt) { self.value = value } 94 | 95 | public var startIndex: Int { return 0 } 96 | public var endIndex: Int { return value.count } 97 | 98 | public subscript(_ index: Int) -> Word { 99 | return value[index] 100 | } 101 | } 102 | 103 | public var words: Words { return Words(self) } 104 | 105 | public init(words: Words) where Words.Element == Word { 106 | let uc = words.underestimatedCount 107 | if uc > 2 { 108 | self.init(words: Array(words)) 109 | } 110 | else { 111 | var it = words.makeIterator() 112 | guard let w0 = it.next() else { 113 | self.init() 114 | return 115 | } 116 | guard let w1 = it.next() else { 117 | self.init(word: w0) 118 | return 119 | } 120 | if let w2 = it.next() { 121 | var words: [UInt] = [] 122 | words.reserveCapacity(Swift.max(3, uc)) 123 | words.append(w0) 124 | words.append(w1) 125 | words.append(w2) 126 | while let word = it.next() { 127 | words.append(word) 128 | } 129 | self.init(words: words) 130 | } 131 | else { 132 | self.init(low: w0, high: w1) 133 | } 134 | } 135 | } 136 | } 137 | 138 | extension BigInt { 139 | public struct Words: RandomAccessCollection { 140 | public typealias Indices = CountableRange 141 | 142 | private let value: BigInt 143 | private let decrementLimit: Int 144 | 145 | fileprivate init(_ value: BigInt) { 146 | self.value = value 147 | switch value.sign { 148 | case .plus: 149 | self.decrementLimit = 0 150 | case .minus: 151 | assert(!value.magnitude.isZero) 152 | self.decrementLimit = value.magnitude.words.firstIndex(where: { $0 != 0 })! 153 | } 154 | } 155 | 156 | public var count: Int { 157 | switch value.sign { 158 | case .plus: 159 | if let high = value.magnitude.words.last, high >> (Word.bitWidth - 1) != 0 { 160 | return value.magnitude.count + 1 161 | } 162 | return value.magnitude.count 163 | case .minus: 164 | let high = value.magnitude.words.last! 165 | if high >> (Word.bitWidth - 1) != 0 { 166 | return value.magnitude.count + 1 167 | } 168 | return value.magnitude.count 169 | } 170 | } 171 | 172 | public var indices: Indices { return 0 ..< count } 173 | public var startIndex: Int { return 0 } 174 | public var endIndex: Int { return count } 175 | 176 | public subscript(_ index: Int) -> UInt { 177 | // Note that indices above `endIndex` are accepted. 178 | if value.sign == .plus { 179 | return value.magnitude[index] 180 | } 181 | if index <= decrementLimit { 182 | return ~(value.magnitude[index] &- 1) 183 | } 184 | return ~value.magnitude[index] 185 | } 186 | } 187 | 188 | public var words: Words { 189 | return Words(self) 190 | } 191 | 192 | public init(words: S) where S.Element == Word { 193 | var words = Array(words) 194 | if (words.last ?? 0) >> (Word.bitWidth - 1) == 0 { 195 | self.init(sign: .plus, magnitude: BigUInt(words: words)) 196 | } 197 | else { 198 | words.twosComplement() 199 | self.init(sign: .minus, magnitude: BigUInt(words: words)) 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Tests/BigIntTests/ProfileTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProfileTests.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2015-12-31. 6 | // Copyright © 2016-2017 Károly Lőrentey. 7 | // 8 | 9 | import XCTest 10 | import BigInt 11 | 12 | #if Profile 13 | 14 | func factorial(_ n: Int) -> BigUInt { 15 | var fact = BigUInt(1) 16 | for i in BigUInt.Word(1) ... BigUInt.Word(n) { 17 | fact.multiply(byWord: i) 18 | } 19 | return fact 20 | } 21 | 22 | class ProfileTests: XCTestCase { 23 | typealias Word = BigUInt.Word 24 | 25 | func measure_(autostart: Bool = true, block: @escaping ()->Void) { 26 | var round = 0 27 | self.measureMetrics(type(of: self).defaultPerformanceMetrics, automaticallyStartMeasuring: autostart) { 28 | print("Round \(round) started") 29 | block() 30 | round += 1 31 | } 32 | } 33 | 34 | func testFibonacciAddition() { 35 | var n1 = BigUInt(1) 36 | var n2 = BigUInt(1) 37 | self.measure { 38 | n1 = BigUInt(1) 39 | n2 = BigUInt(1) 40 | for i in 0..<200000 { 41 | if i & 1 == 0 { 42 | n1 += n2 43 | } 44 | else { 45 | n2 += n1 46 | } 47 | } 48 | } 49 | noop(n1) 50 | noop(n2) 51 | } 52 | 53 | func checkFactorial(fact: BigUInt, n: Int, file: StaticString = #file, line: UInt = #line) { 54 | var remaining = fact 55 | for i in 1...n { 56 | let (div, mod) = remaining.quotientAndRemainder(dividingBy: BigUInt(i)) 57 | XCTAssertEqual(mod, 0, "for divisor = \(i)", file: file, line: line) 58 | remaining = div 59 | } 60 | XCTAssertEqual(remaining, 1, file: file, line: line) 61 | } 62 | 63 | func testDivisionOfFactorial() { 64 | let n = 32767 65 | let fact = factorial(n) 66 | self.measure { 67 | checkFactorial(fact: fact, n: n) 68 | } 69 | } 70 | 71 | func testPrintingFactorial() { 72 | let n = 32767 73 | let fact = factorial(n) 74 | var string: String = "" 75 | self.measure { 76 | string = String(fact, radix: 10) 77 | } 78 | XCTAssertEqual(BigUInt(string, radix: 10), fact) 79 | } 80 | 81 | func testReadingFactorial() { 82 | let n = 32767 83 | let fact = factorial(n) 84 | let string = String(fact, radix: 10) 85 | print(string) 86 | self.measure { 87 | XCTAssertEqual(BigUInt(string, radix: 10), fact) 88 | } 89 | } 90 | 91 | func testFactorial() { 92 | var fact = BigUInt() 93 | let n = 32767 94 | self.measure { 95 | fact = factorial(n) 96 | } 97 | checkFactorial(fact: fact, n: n) 98 | } 99 | 100 | func testBalancedFactorial() { 101 | func balancedFactorial(level: Int, offset: Int = 0) -> BigUInt { 102 | if level == 0 { 103 | return BigUInt(offset == 0 ? 1 : offset) 104 | } 105 | let a = balancedFactorial(level: level - 1, offset: 2 * offset) 106 | let b = balancedFactorial(level: level - 1, offset: 2 * offset + 1) 107 | return a * b 108 | } 109 | 110 | let power = 15 111 | 112 | var fact = BigUInt() 113 | self.measure { 114 | fact = balancedFactorial(level: power) 115 | } 116 | checkFactorial(fact: fact, n: ((1 as Int) << power) - 1) 117 | } 118 | 119 | func testDivision() { 120 | var divisors: [BigUInt] = [] 121 | func balancedFactorial(level: Int, offset: Int = 0) -> BigUInt { 122 | if level == 0 { 123 | return BigUInt(offset == 0 ? 1 : offset) 124 | } 125 | let a = balancedFactorial(level: level - 1, offset: 2 * offset) 126 | let b = balancedFactorial(level: level - 1, offset: 2 * offset + 1) 127 | let p = a * b 128 | if level >= 10 { divisors.append(p) } 129 | return p 130 | } 131 | 132 | let power = 14 133 | 134 | let fact = balancedFactorial(level: power) 135 | print("Performing \(divisors.count) divisions with digit counts (\(fact.words.count) / (\(divisors[0].words.count)...\(divisors[divisors.count - 1].words.count))") 136 | var divs: [BigUInt] = [] 137 | var mods: [BigUInt] = [] 138 | divs.reserveCapacity(divisors.count) 139 | mods.reserveCapacity(divisors.count) 140 | self.measure_(autostart: false) { 141 | divs.removeAll() 142 | mods.removeAll() 143 | self.startMeasuring() 144 | for divisor in divisors { 145 | let (div, mod) = fact.quotientAndRemainder(dividingBy: divisor) 146 | divs.append(div) 147 | mods.append(mod) 148 | } 149 | self.stopMeasuring() 150 | } 151 | for i in 0.. [BigUInt] { 158 | var rnd = PseudoRandomNumbers(seed: seed) 159 | return (0 ..< count).map { _ in BigUInt(words: (0 ..< words).map { _ in rnd.next()! }) } 160 | } 161 | 162 | func testSquareRoot() { 163 | let numbers = randomBigUInts(1000, seed: 42, withMaxWords: 60) 164 | var roots: [BigUInt] = [] 165 | self.measure { 166 | roots.removeAll() 167 | for number in numbers { 168 | let root = number.squareRoot() 169 | roots.append(root) 170 | } 171 | } 172 | 173 | for i in 0.. = [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281] 220 | for exp in 1...1000 { 221 | let mersenne = BigUInt(1) << exp - 1 222 | XCTAssertEqual(mersenne.isPrime(), exponents.contains(exp), "\(exp) smells fishy") 223 | } 224 | // Seems legit. You win this round, evil magmaticians 225 | } 226 | } 227 | } 228 | #endif 229 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Tools.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tools.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-7-23. 6 | // Copyright © 2017 Károly Lőrentey. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | 11 | @inline(never) 12 | func noop(_ value: T) { 13 | _ = value 14 | } 15 | 16 | // A basic low-quality random number generator. 17 | struct PseudoRandomNumbers: Sequence, IteratorProtocol { 18 | typealias Element = BigUInt.Word 19 | var last: Element 20 | 21 | init(seed: Element) { 22 | self.last = seed 23 | } 24 | 25 | mutating func next() -> Element? { 26 | // Constants are from Knuth's MMIX and Numerical Recipes, respectively 27 | let a: Element = (Element.bitWidth == 8 ? 6364136223846793005 : 1664525) 28 | let c: Element = (Element.bitWidth == 8 ? 1442695040888963407 : 1013904223) 29 | last = a &* last &+ c 30 | return last 31 | } 32 | } 33 | 34 | func convertWords(_ wideWords: S) -> [UInt] where S.Element == UInt64 { 35 | return wideWords.flatMap { $0.words } 36 | } 37 | 38 | extension String { 39 | func repeated(_ count: Int) -> String { 40 | var result = "" 41 | for _ in 0 ..< count { 42 | result += self 43 | } 44 | return result 45 | } 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet - Helpers/BitWidthTestCases.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | @testable import BigInt 5 | 6 | internal enum BitWidthTestCases { 7 | 8 | // MARK: - Smi 9 | 10 | internal typealias SmiTestCase = (value: Int, expected: Int) 11 | 12 | internal static let smi: [SmiTestCase] = [ 13 | // zero 14 | (0, 1), 15 | // positive 16 | (1, 2), 17 | (2, 3), 18 | (3, 3), 19 | (4, 4), 20 | (5, 4), 21 | (6, 4), 22 | (7, 4), 23 | (8, 5), 24 | (9, 5), 25 | (10, 5), 26 | (11, 5), 27 | (12, 5), 28 | (13, 5), 29 | (14, 5), 30 | (15, 5), 31 | // negative 32 | (-1, 1), 33 | (-2, 2), 34 | (-3, 3), 35 | (-4, 3), 36 | (-5, 4), 37 | (-6, 4), 38 | (-7, 4), 39 | (-8, 4), 40 | (-9, 5), 41 | (-10, 5), 42 | (-11, 5), 43 | (-12, 5), 44 | (-13, 5), 45 | (-14, 5), 46 | (-15, 5) 47 | ] 48 | 49 | // MARK: - Powers of 2 50 | 51 | internal typealias PowerTestCase = (value: Int, power: Int, expected: Int) 52 | 53 | // +-----+-----------+-------+-------+ 54 | // | dec | bin | power | bit | 55 | // | | | | width | 56 | // +-----+-----------+-------+-------+ 57 | // | 1 | 0001 | 0 | 2 | 58 | // | 2 | 0010 | 1 | 3 | 59 | // | 4 | 0100 | 2 | 4 | 60 | // | 8 | 0000 1000 | 3 | 5 | 61 | // +-----+-----------+-------+-------+ 62 | // TLDR: bitWidth = power + 2 63 | internal static let positivePowersOf2Correction = 2 64 | 65 | internal static var positivePowersOf2: [PowerTestCase] = { 66 | var result = [PowerTestCase]() 67 | 68 | for (power, value) in allPositivePowersOf2(type: Int.self) { 69 | let bitWidth = power + Self.positivePowersOf2Correction 70 | let tuple = (value, power, bitWidth) 71 | result.append(tuple) 72 | } 73 | 74 | return result 75 | }() 76 | 77 | // +-----+------+-------+-------+ 78 | // | dec | bin | power | bit | 79 | // | | | | width | 80 | // +-----+------+-------+-------+ 81 | // | -1 | 1111 | 0 | 1 | 82 | // | -2 | 1110 | 1 | 2 | 83 | // | -4 | 1100 | 2 | 3 | 84 | // | -8 | 1000 | 3 | 4 | 85 | // +-----+------+-------+-------+ 86 | // TLDR: bitWidth = power + 1 87 | internal static let negativePowersOf2Correction = 1 88 | 89 | internal static var negativePowersOf2: [PowerTestCase] = { 90 | var result = [PowerTestCase]() 91 | 92 | for (power, value) in allNegativePowersOf2(type: Int.self) { 93 | let bitWidth = power + Self.negativePowersOf2Correction 94 | let tuple = (value, power, bitWidth) 95 | result.append(tuple) 96 | } 97 | 98 | return result 99 | }() 100 | } 101 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet - Helpers/GenerateValues.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | @testable import BigInt 5 | 6 | // MARK: - Int 7 | 8 | /// Will return `2 * countButNotReally + 3` values (don't ask). 9 | internal func generateIntValues(countButNotReally: Int) -> [Int] { 10 | return generateValues( 11 | countButNotReally: countButNotReally, 12 | type: Int.self 13 | ) 14 | } 15 | 16 | private func generateValues( 17 | countButNotReally: Int, 18 | type: T.Type 19 | ) -> [T] { 20 | assert(countButNotReally > 0) 21 | 22 | var result = [T]() 23 | result.append(0) 24 | result.append(1) 25 | result.append(-1) 26 | 27 | let step = Int(T.max) / countButNotReally 28 | 29 | // 1st iteration will append 'T.min' and 'T.max' 30 | for i in 0.. BigInt { 63 | let sign: BigInt.Sign = self.isNegative ? .minus : .plus 64 | let magnitude = BigUInt(words: self.words) 65 | return BigInt(sign: sign, magnitude: magnitude) 66 | } 67 | } 68 | 69 | /// Will return `2 * countButNotReally + 5` values (don't ask). 70 | /// 71 | /// We do not return `BigInt` directly because in some cases 72 | /// (for example equality tests) you may want to create more than 1 value 73 | /// INDEPENDENTLY. 74 | internal func generateBigIntValues(countButNotReally: Int, 75 | maxWordCount: Int = 3) -> [BigIntPrototype] { 76 | var result = [BigIntPrototype]() 77 | result.append(BigIntPrototype(isNegative: false, words: [])) // 0 78 | result.append(BigIntPrototype(isNegative: false, words: [1])) // 1 79 | result.append(BigIntPrototype(isNegative: true, words: [1])) // -1 80 | result.append(BigIntPrototype(isNegative: false, words: [.max])) // Word.max 81 | result.append(BigIntPrototype(isNegative: true, words: [.max])) // -Word.max 82 | 83 | var word = BigInt.Word(2) // Start from '2' and go up 84 | for i in 0..: Sequence { 7 | 8 | internal typealias Element = (T, V) 9 | 10 | internal struct Iterator: IteratorProtocol { 11 | 12 | private let lhsValues: [T] 13 | private let rhsValues: [V] 14 | 15 | private var lhsIndex = 0 16 | private var rhsIndex = 0 17 | 18 | fileprivate init(lhs: [T], rhs: [V]) { 19 | self.lhsValues = lhs 20 | self.rhsValues = rhs 21 | } 22 | 23 | internal mutating func next() -> Element? { 24 | if self.lhsIndex == self.lhsValues.count { 25 | return nil 26 | } 27 | 28 | let lhs = self.lhsValues[self.lhsIndex] 29 | let rhs = self.rhsValues[self.rhsIndex] 30 | 31 | self.rhsIndex += 1 32 | if self.rhsIndex == self.rhsValues.count { 33 | self.lhsIndex += 1 34 | self.rhsIndex = 0 35 | } 36 | 37 | return (lhs, rhs) 38 | } 39 | } 40 | 41 | private let lhsValues: [T] 42 | private let rhsValues: [V] 43 | 44 | fileprivate init(lhs: [T], rhs: [V]) { 45 | self.lhsValues = lhs 46 | self.rhsValues = rhs 47 | } 48 | 49 | internal func makeIterator() -> Iterator { 50 | return Iterator(lhs: self.lhsValues, rhs: self.rhsValues) 51 | } 52 | } 53 | 54 | /// `[1, 2] -> [(1,1), (1,2), (2,1), (2,2)]` 55 | internal func allPossiblePairings(values: [T]) -> PossiblePairings { 56 | return PossiblePairings(lhs: values, rhs: values) 57 | } 58 | 59 | /// `[1, 2], [1, 2] -> [(1,1), (1,2), (2,1), (2,2)]` 60 | internal func allPossiblePairings(lhs: [T], rhs: [S]) -> PossiblePairings { 61 | return PossiblePairings(lhs: lhs, rhs: rhs) 62 | } 63 | 64 | // MARK: - Powers of 2 65 | 66 | internal typealias PowerOf2 = (power: Int, value: T) 67 | 68 | /// `1, 2, 4, 8, 16, 32, 64, 128, 256, 512, etc…` 69 | internal func allPositivePowersOf2( 70 | type: T.Type 71 | ) -> [PowerOf2] { 72 | var result = [PowerOf2]() 73 | result.reserveCapacity(T.bitWidth) 74 | 75 | var value = T(1) 76 | var power = 0 77 | result.append(PowerOf2(power: power, value: value)) 78 | 79 | while true { 80 | let (newValue, overflow) = value.multipliedReportingOverflow(by: 2) 81 | if overflow { 82 | return result 83 | } 84 | 85 | value = newValue 86 | power += 1 87 | result.append(PowerOf2(power: power, value: value)) 88 | } 89 | } 90 | 91 | /// `-1, -2, -4, -8, -16, -32, -64, -128, -256, -512, etc…` 92 | internal func allNegativePowersOf2( 93 | type: T.Type 94 | ) -> [PowerOf2] { 95 | assert(T.isSigned) 96 | 97 | var result = [PowerOf2]() 98 | result.reserveCapacity(T.bitWidth) 99 | 100 | var value = T(-1) 101 | var power = 0 102 | result.append(PowerOf2(power: power, value: value)) 103 | 104 | while true { 105 | let (newValue, overflow) = value.multipliedReportingOverflow(by: 2) 106 | if overflow { 107 | return result 108 | } 109 | 110 | value = newValue 111 | power += 1 112 | result.append(PowerOf2(power: power, value: value)) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet - Helpers/WordsTestCases.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | import XCTest 5 | @testable import BigInt 6 | 7 | // MARK: - Asserts 8 | 9 | internal func XCTAssertWords(_ value: BigInt, 10 | _ expected: [UInt], 11 | file: StaticString = #file, 12 | line: UInt = #line) { 13 | XCTAssertWords( 14 | value: String(value, radix: 10, uppercase: false), 15 | words: Array(value.words), 16 | expected: expected, 17 | file: file, 18 | line: line 19 | ) 20 | } 21 | 22 | private func XCTAssertWords(value: String, 23 | words: [UInt], 24 | expected: [UInt], 25 | file: StaticString, 26 | line: UInt) { 27 | XCTAssertEqual(words.count, expected.count, "Count for \(value)", file: file, line: line) 28 | guard words.count == expected.count else { 29 | return 30 | } 31 | 32 | // deconstruction nested in deconstruction? eh… 33 | for (index, (w, e)) in zip(words, expected).enumerated() { 34 | XCTAssertEqual(w, e, "Word \(index) for \(value)", file: file, line: line) 35 | } 36 | } 37 | 38 | // MARK: - Test cases 39 | 40 | internal enum WordsTestCases { 41 | 42 | // MARK: - Zero 43 | 44 | internal static let zeroWords: [UInt] = [0] 45 | 46 | // MARK: - Int 47 | 48 | internal typealias IntTestCase = (value: Int, expected: [UInt]) 49 | 50 | internal static let int: [IntTestCase] = { 51 | var result = [IntTestCase]() 52 | 53 | for int in generateIntValues(countButNotReally: 100) { 54 | let expected = Array(int.words) 55 | let tuple = IntTestCase(int, expected) 56 | result.append(tuple) 57 | } 58 | 59 | return result 60 | }() 61 | 62 | // MARK: - Heap positive 63 | 64 | internal typealias Word = BigInt.Word 65 | 66 | internal typealias HeapTestCase = (words: [Word], expected: [UInt]) 67 | 68 | // words: 1000 0000 69 | internal static var heapPositive: [HeapTestCase] = { 70 | var result = [HeapTestCase]() 71 | 72 | for zeroWordCount in [1, 2] { 73 | let zeroWords = [Word](repeating: 0, count: zeroWordCount) 74 | 75 | for (_, value) in allPositivePowersOf2(type: Word.self) { 76 | let words = zeroWords + [value] 77 | 78 | let hasMsb1 = (value >> (Word.bitWidth - 1)) == 1 79 | let needsSignWord = hasMsb1 80 | let expectedWords = needsSignWord ? words + [0] : words 81 | 82 | let tuple = HeapTestCase(words, expectedWords) 83 | result.append(tuple) 84 | } 85 | } 86 | 87 | return result 88 | }() 89 | 90 | // MARK: - Heap negative 91 | 92 | // words: 1000 0000 93 | // invert: 0111 1111 94 | // complement: 1000 0000 95 | internal static var heapNegative_powerOf2: [HeapTestCase] = { 96 | var result = [HeapTestCase]() 97 | 98 | for zeroWordCount in [1, 2] { 99 | let zeroWords = [Word](repeating: 0, count: zeroWordCount) 100 | 101 | for (_, value) in allPositivePowersOf2(type: Word.self) { 102 | let words = zeroWords + [value] 103 | 104 | let valueCompliment = ~value + 1 105 | let expectedWords = zeroWords + [valueCompliment] 106 | 107 | let tuple = HeapTestCase(words, expectedWords) 108 | result.append(tuple) 109 | } 110 | } 111 | 112 | return result 113 | }() 114 | 115 | // case 1: most common 116 | // words: 0100 0001 117 | // invert: 1011 1110 118 | // complement: 1011 1111 119 | // 120 | // case 2: needs sign word 121 | // words: 1000 0001 122 | // invert: 0111 1110 123 | // complement: 1111 0111 1111 124 | internal static var heapNegative_notPowerOf2: [HeapTestCase] = { 125 | var result = [HeapTestCase]() 126 | 127 | for zeroWordCount in [1, 2] { 128 | // We are not power of '2', so we have to modify 'zeroWords' 129 | var zeroWords = [Word](repeating: 0, count: zeroWordCount) 130 | zeroWords[0] = 1 131 | 132 | let all1 = Word.max 133 | let complementWords = [Word](repeating: all1, count: zeroWordCount) 134 | 135 | for (_, value) in allPositivePowersOf2(type: Word.self) { 136 | let words = zeroWords + [value] 137 | 138 | let hasMsb1 = (value >> (Word.bitWidth - 1)) == 1 139 | let needsSignWord = hasMsb1 140 | let expectedWords = needsSignWord ? 141 | complementWords + [~value, all1] : 142 | complementWords + [~value] 143 | 144 | let tuple = HeapTestCase(words, expectedWords) 145 | result.append(tuple) 146 | } 147 | } 148 | 149 | return result 150 | }() 151 | } 152 | 153 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet - Property testing/ApplyA_UndoA.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | import XCTest 5 | @testable import BigInt 6 | 7 | // swiftlint:disable type_name 8 | 9 | private typealias Word = BigInt.Word 10 | 11 | /// Operations for which exists 'reverse' operation that undoes its effect. 12 | /// For example for addition it is subtraction: `(n + x) - x = n`. 13 | class ApplyA_UndoA: XCTestCase { 14 | 15 | private lazy var values = generateBigIntValues(countButNotReally: 20) 16 | private lazy var pairs = allPossiblePairings(lhs: self.values, rhs: self.values) 17 | 18 | // MARK: - Tests 19 | 20 | func test_addSub() { 21 | for (lhsRaw, rhsRaw) in self.pairs { 22 | let lhs = self.create(lhsRaw) 23 | let rhs = self.create(rhsRaw) 24 | 25 | let expectedLhs = (lhs + rhs) - rhs 26 | XCTAssertEqual(lhs, expectedLhs, "\(lhs) +- \(rhs)") 27 | } 28 | } 29 | 30 | func test_mulDiv() { 31 | for (lhsRaw, rhsRaw) in self.pairs { 32 | if rhsRaw.isZero { 33 | continue 34 | } 35 | 36 | let lhs = self.create(lhsRaw) 37 | let rhs = self.create(rhsRaw) 38 | 39 | let expectedLhs = (lhs * rhs) / rhs 40 | XCTAssertEqual(lhs, expectedLhs, "\(lhs) */ \(rhs)") 41 | } 42 | } 43 | 44 | func test_shiftLeftRight() { 45 | for raw in self.values { 46 | let value = self.create(raw) 47 | 48 | let lessThanWord = 5 49 | let word = Word.bitWidth 50 | let moreThanWord = Word.bitWidth + Word.bitWidth - 7 51 | 52 | for count in [lessThanWord, word, moreThanWord] { 53 | let result = (value << count) >> count 54 | XCTAssertEqual(result, value, "\(value) <<>> \(count)") 55 | } 56 | } 57 | } 58 | 59 | func test_toStringInit() { 60 | for raw in self.values { 61 | let value = self.create(raw) 62 | 63 | for radix in [2, 5, 10, 16] { 64 | let string = String(value, radix: radix) 65 | guard let int = BigInt(string, radix: radix) else { 66 | XCTFail("string: \(string), radix: \(radix)") 67 | continue 68 | } 69 | 70 | XCTAssertEqual(int, value, "string: \(string)") 71 | } 72 | } 73 | } 74 | 75 | // MARK: - Helpers 76 | 77 | private func create(_ p: BigIntPrototype) -> BigInt { 78 | return p.create() 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet/BigIntHashTests.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | import XCTest 5 | @testable import BigInt 6 | 7 | // Well… actually… hash and equatable 8 | class BigIntHashTests: XCTestCase { 9 | 10 | private let smis = generateIntValues(countButNotReally: 50) 11 | private let heaps = generateBigIntValues(countButNotReally: 50) 12 | 13 | // Values that are in both `smis` and `heaps`. 14 | private lazy var common: [BigInt] = { 15 | var result = [BigInt]() 16 | let smiSet = Set(self.smis) 17 | 18 | for p in self.heaps { 19 | let heap = p.create() 20 | if let int = Int(exactly: heap), smiSet.contains(int) { 21 | result.append(heap) 22 | } 23 | } 24 | 25 | return result 26 | }() 27 | 28 | private var scalars: [UnicodeScalar] = { 29 | let asciiStart: UInt8 = 0x21 // ! 30 | let asciiEnd: UInt8 = 0x7e // ~ 31 | let result = (asciiStart...asciiEnd).map { UnicodeScalar($0) } 32 | return result + result // to be sure that it is more than 'self.smis.count' 33 | }() 34 | 35 | // MARK: - Set 36 | 37 | func test_set_insertAndFind() { 38 | // Insert all of the values 39 | var set = Set() 40 | self.insert(&set, values: self.smis) 41 | self.insert(&set, values: self.heaps) 42 | 43 | let expectedCount = self.smis.count + self.heaps.count - self.common.count 44 | XCTAssertEqual(set.count, expectedCount) 45 | 46 | // Check if we can find them 47 | for value in self.smis { 48 | let int = self.create(value) 49 | XCTAssert(set.contains(int), "\(value)") 50 | } 51 | 52 | for value in self.heaps { 53 | let int = self.create(value) 54 | XCTAssert(set.contains(int), "\(int)") 55 | } 56 | } 57 | 58 | func test_set_insertAndRemove() { 59 | // Insert all of the values 60 | var set = Set() 61 | self.insert(&set, values: self.smis) 62 | self.insert(&set, values: self.heaps) 63 | 64 | let allCount = self.smis.count + self.heaps.count - self.common.count 65 | XCTAssertEqual(set.count, allCount) 66 | 67 | // And now remove them 68 | for value in self.smis { 69 | let int = self.create(value) 70 | let existing = set.remove(int) 71 | XCTAssertNotNil(existing, "Missing: \(value)") 72 | } 73 | 74 | let withoutSmiCount = self.heaps.count - self.common.count 75 | XCTAssertEqual(set.count, withoutSmiCount) 76 | 77 | for value in self.heaps { 78 | let int = self.create(value) 79 | let wasAlreadyRemoved = self.common.contains(int) 80 | 81 | if !wasAlreadyRemoved { 82 | let existing = set.remove(int) 83 | XCTAssertNotNil(existing, "Missing: \(int)") 84 | } 85 | } 86 | 87 | XCTAssert(set.isEmpty) 88 | } 89 | 90 | // MARK: - Dict 91 | 92 | func test_dict_insertAndFind() { 93 | // Insert all of the numbers to dict 94 | var dict = [BigInt: UnicodeScalar]() 95 | self.insert(&dict, values: zip(self.smis, self.scalars)) 96 | self.insert(&dict, values: zip(self.heaps, self.scalars), excluding: self.common) 97 | 98 | let expectedCount = self.smis.count + self.heaps.count - self.common.count 99 | XCTAssertEqual(dict.count, expectedCount) 100 | 101 | // Check if we can find all of the elements 102 | for (value, char) in zip(self.smis, self.scalars) { 103 | let int = self.create(value) 104 | 105 | if let result = dict[int] { 106 | XCTAssertEqual(result, char, "key: \(int)") 107 | } else { 108 | XCTFail("missing: \(int)") 109 | } 110 | } 111 | 112 | for (value, char) in zip(self.heaps, self.scalars) { 113 | let int = self.create(value) 114 | 115 | if self.common.contains(int) { 116 | // It was already checked in 'smi' loop 117 | } else if let result = dict[int] { 118 | XCTAssertEqual(result, char, "key: \(int)") 119 | } else { 120 | XCTFail("missing: \(int)") 121 | } 122 | } 123 | } 124 | 125 | func test_dict_insertAndRemove() { 126 | // Insert all of the numbers to dict 127 | var dict = [BigInt: UnicodeScalar]() 128 | self.insert(&dict, values: zip(self.smis, self.scalars)) 129 | self.insert(&dict, values: zip(self.heaps, self.scalars), excluding: self.common) 130 | 131 | let expectedCount = self.smis.count + self.heaps.count - self.common.count 132 | XCTAssertEqual(dict.count, expectedCount) 133 | 134 | // And now remove them 135 | for value in self.smis { 136 | let int = self.create(value) 137 | let existing = dict.removeValue(forKey: int) 138 | XCTAssertNotNil(existing, "Missing: \(value)") 139 | } 140 | 141 | let withoutSmiCount = self.heaps.count - self.common.count 142 | XCTAssertEqual(dict.count, withoutSmiCount) 143 | 144 | for value in self.heaps { 145 | let int = self.create(value) 146 | let wasAlreadyRemoved = self.common.contains(int) 147 | 148 | if !wasAlreadyRemoved { 149 | let existing = dict.removeValue(forKey: int) 150 | XCTAssertNotNil(existing, "Missing: \(int)") 151 | } 152 | } 153 | 154 | XCTAssert(dict.isEmpty) 155 | } 156 | 157 | func test_dict_insertReplaceAndFind() { 158 | // Insert all of the numbers to dict 159 | var dict = [BigInt: UnicodeScalar]() 160 | self.insert(&dict, values: zip(self.smis, self.scalars)) 161 | self.insert(&dict, values: zip(self.heaps, self.scalars), excluding: self.common) 162 | 163 | let expectedCount = self.smis.count + self.heaps.count - self.common.count 164 | XCTAssertEqual(dict.count, expectedCount) 165 | 166 | // Replace the values 167 | let reversedScalars = self.scalars.reversed() 168 | self.insert(&dict, values: zip(self.smis, reversedScalars)) 169 | self.insert(&dict, values: zip(self.heaps, reversedScalars), excluding: self.common) 170 | 171 | // Count should have not changed 172 | XCTAssertEqual(dict.count, expectedCount) 173 | 174 | // Check if we can find all of the elements 175 | for (value, char) in zip(self.smis, reversedScalars) { 176 | let int = self.create(value) 177 | 178 | if let result = dict[int] { 179 | XCTAssertEqual(result, char, "key: \(int)") 180 | } else { 181 | XCTFail("missing: \(int)") 182 | } 183 | } 184 | 185 | for (value, char) in zip(self.heaps, reversedScalars) { 186 | let int = self.create(value) 187 | 188 | if self.common.contains(int) { 189 | // It was already checked in 'smi' loop 190 | } else if let result = dict[int] { 191 | XCTAssertEqual(result, char, "key: \(int)") 192 | } else { 193 | XCTFail("missing: \(int)") 194 | } 195 | } 196 | } 197 | 198 | // MARK: - Helpers 199 | 200 | private func insert(_ set: inout Set, values: [Int]) { 201 | for value in values { 202 | let int = self.create(value) 203 | set.insert(int) 204 | } 205 | } 206 | 207 | private func insert(_ set: inout Set, values: [BigIntPrototype]) { 208 | for value in values { 209 | let int = self.create(value) 210 | set.insert(int) 211 | } 212 | } 213 | 214 | private func insert( 215 | _ dict: inout [BigInt: UnicodeScalar], 216 | values: S 217 | ) where S.Element == (Int, UnicodeScalar) { 218 | for (value, char) in values { 219 | let int = self.create(value) 220 | dict[int] = char 221 | } 222 | } 223 | 224 | private func insert( 225 | _ dict: inout [BigInt: UnicodeScalar], 226 | values: S, 227 | excluding: [BigInt] 228 | ) where S.Element == (BigIntPrototype, UnicodeScalar) { 229 | for (value, char) in values { 230 | let int = self.create(value) 231 | if !excluding.contains(int) { 232 | dict[int] = char 233 | } 234 | } 235 | } 236 | 237 | private func create(_ value: Int) -> BigInt { 238 | return BigInt(value) 239 | } 240 | 241 | private func create(_ p: BigIntPrototype) -> BigInt { 242 | let heap = p.create() 243 | return BigInt(heap) 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet/BigIntPowerTests.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | import XCTest 5 | @testable import BigInt 6 | 7 | class BigIntPowerTests: XCTestCase { 8 | 9 | // MARK: - Trivial base 10 | 11 | /// 0 ^ n = 0 (or sometimes 1) 12 | // func test_base_zero() { 13 | // let zero = BigInt(0) 14 | // let one = BigInt(1) 15 | // 16 | // for exponent in generateIntValues(countButNotReally: 100) { 17 | // let result = zero.power(exponent) 18 | // 19 | // // 0 ^ 0 = 1, otherwise 0 20 | // let expected = exponent == 0 ? one : zero 21 | // XCTAssertEqual(result, expected, "0 ^ \(exponent)") 22 | // } 23 | // } 24 | 25 | /// 1 ^ n = 1 26 | func test_base_one() { 27 | let one = BigInt(1) 28 | 29 | for exponent in generateIntValues(countButNotReally: 100) { 30 | let result = one.power(exponent) 31 | let expected = one 32 | XCTAssertEqual(result, expected, "1 ^ \(exponent)") 33 | } 34 | } 35 | 36 | /// (-1) ^ n = (-1) or 1 37 | func test_base_minusOne() { 38 | let plusOne = BigInt(1) 39 | let minusOne = BigInt(-1) 40 | 41 | for exponent in generateIntValues(countButNotReally: 100) { 42 | let result = minusOne.power(exponent) 43 | 44 | let expected = exponent.isMultiple(of: 2) ? plusOne : minusOne 45 | XCTAssertEqual(result, expected, "(-1) ^ \(exponent)") 46 | } 47 | } 48 | 49 | // MARK: - Trivial exponent 50 | 51 | /// n ^ 0 = 1 52 | func test_exponent_zero() { 53 | let zero = 0 54 | let one = BigInt(1) 55 | 56 | for smi in generateIntValues(countButNotReally: 100) { 57 | let base = BigInt(smi) 58 | let result = base.power(zero) 59 | 60 | let expected = one 61 | XCTAssertEqual(result, expected, "\(smi) ^ 1") 62 | } 63 | } 64 | 65 | /// n ^ 1 = n 66 | func test_exponent_one() { 67 | let one = 1 68 | 69 | for smi in generateIntValues(countButNotReally: 100) { 70 | let base = BigInt(smi) 71 | let result = base.power(one) 72 | 73 | let expected = base 74 | XCTAssertEqual(result, expected, "\(smi) ^ 1") 75 | } 76 | } 77 | 78 | func test_exponent_two() { 79 | let two = 2 80 | 81 | for p in generateBigIntValues(countButNotReally: 2) { 82 | let baseHeap = BigIntPrototype(isNegative: false, words: p.words) 83 | let base = baseHeap.create() 84 | let result = base.power(two) 85 | 86 | let expected = base * base 87 | XCTAssertEqual(result, expected, "\(base) ^ 2") 88 | } 89 | } 90 | 91 | func test_exponent_three() { 92 | let three = 3 93 | 94 | for p in generateBigIntValues(countButNotReally: 2) { 95 | let baseHeap = BigIntPrototype(isNegative: false, words: p.words) 96 | let base = baseHeap.create() 97 | let result = base.power(three) 98 | 99 | let expected = base * base * base 100 | XCTAssertEqual(result, expected, "\(base) ^ 3") 101 | } 102 | } 103 | 104 | // MARK: - Smi 105 | 106 | func test_againstFoundationPow() { 107 | // THIS IS NOT A PERFECT TEST! 108 | // It is 'good enough' to be usable, but don't think about it too much! 109 | let mantissaCount = Double.significandBitCount // well… technically '+1' 110 | let maxExactlyRepresentable = UInt(pow(Double(2), Double(mantissaCount))) 111 | 112 | // 'Int32 ^ 2' has greater possibility of being in 'Double' range than 'Int' 113 | var values = [Int32]() 114 | 115 | for value in generateIntValues(countButNotReally: 20) { 116 | if let i32 = Int32(exactly: value) { 117 | values.append(i32) 118 | } 119 | } 120 | 121 | for i in -10...10 { 122 | values.append(Int32(i)) 123 | } 124 | 125 | for (baseSmi, expSmiSigned) in allPossiblePairings(values: values) { 126 | let expSmi = expSmiSigned.magnitude 127 | 128 | guard let baseDouble = Double(exactly: baseSmi), 129 | let expDouble = Double(exactly: expSmi) else { 130 | continue 131 | } 132 | 133 | let expectedDouble = pow(baseDouble, expDouble) 134 | guard let expectedInt = Int(exactly: expectedDouble), 135 | expectedInt.magnitude < maxExactlyRepresentable else { 136 | continue 137 | } 138 | 139 | // Some tests will actually get here, not a lot, but some 140 | let base = BigInt(baseSmi) 141 | let exp = Int(expSmi) 142 | let result = base.power(exp) 143 | 144 | let expected = BigInt(expectedInt) 145 | XCTAssertEqual(result, expected, "\(baseSmi) ^ \(expSmi)") 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Tests/BigIntTests/Violet/BigIntPropertyTests.swift: -------------------------------------------------------------------------------- 1 | // This file was written by LiarPrincess for Violet - Python VM written in Swift. 2 | // https://github.com/LiarPrincess/Violet 3 | 4 | import XCTest 5 | @testable import BigInt 6 | 7 | private typealias Word = BigInt.Word 8 | 9 | class BigIntPropertyTests: XCTestCase { 10 | 11 | // MARK: - Description 12 | 13 | func test_description() { 14 | for int in generateIntValues(countButNotReally: 100) { 15 | let value = BigInt(int) 16 | XCTAssertEqual(value.description, int.description, "\(int)") 17 | } 18 | } 19 | 20 | // MARK: - Words 21 | 22 | // func test_words_zero() { 23 | // let value = BigInt(0) 24 | // XCTAssertWords(value, WordsTestCases.zeroWords) 25 | // } 26 | // 27 | // func test_words_int() { 28 | // for (value, expected) in WordsTestCases.int { 29 | // let bigInt = BigInt(value) 30 | // XCTAssertWords(bigInt, expected) 31 | // } 32 | // } 33 | 34 | func test_words_multipleWords_positive() { 35 | for (words, expected) in WordsTestCases.heapPositive { 36 | let heap = BigIntPrototype(isNegative: false, words: words) 37 | let bigInt = heap.create() 38 | XCTAssertWords(bigInt, expected) 39 | } 40 | } 41 | 42 | // func test_words_multipleWords_negative_powerOf2() { 43 | // for (words, expected) in WordsTestCases.heapNegative_powerOf2 { 44 | // let heap = BigIntPrototype(isNegative: true, words: words) 45 | // let bigInt = heap.create() 46 | // XCTAssertWords(bigInt, expected) 47 | // } 48 | // } 49 | 50 | func test_words_multipleWords_negative_notPowerOf2() { 51 | for (words, expected) in WordsTestCases.heapNegative_notPowerOf2 { 52 | let heap = BigIntPrototype(isNegative: true, words: words) 53 | let bigInt = heap.create() 54 | XCTAssertWords(bigInt, expected) 55 | } 56 | } 57 | 58 | // MARK: - Bit width 59 | 60 | // func test_bitWidth_trivial() { 61 | // let zero = BigInt(0) 62 | // XCTAssertEqual(zero.bitWidth, 1) // 0 is just 0 63 | // 64 | // let plus1 = BigInt(1) 65 | // XCTAssertEqual(plus1.bitWidth, 2) // 1 needs '0' prefix -> '01' 66 | // 67 | // let minus1 = BigInt(-1) 68 | // XCTAssertEqual(minus1.bitWidth, 1) // -1 is just 1 69 | // } 70 | 71 | func test_bitWidth_positivePowersOf2() { 72 | for (int, power, expected) in BitWidthTestCases.positivePowersOf2 { 73 | let bigInt = BigInt(int) 74 | XCTAssertEqual(bigInt.bitWidth, expected, "for \(int) (2^\(power))") 75 | } 76 | } 77 | 78 | // func test_bitWidth_negativePowersOf2() { 79 | // for (int, power, expected) in BitWidthTestCases.negativePowersOf2 { 80 | // let bigInt = BigInt(int) 81 | // XCTAssertEqual(bigInt.bitWidth, expected, "for \(int) (2^\(power))") 82 | // } 83 | // } 84 | // 85 | // func test_bitWidth_smiTestCases() { 86 | // for (value, expected) in BitWidthTestCases.smi { 87 | // let bigInt = BigInt(value) 88 | // XCTAssertEqual(bigInt.bitWidth, expected, "\(value)") 89 | // } 90 | // } 91 | 92 | func test_bitWidth_multipleWords_positivePowersOf2() { 93 | let correction = BitWidthTestCases.positivePowersOf2Correction 94 | 95 | for zeroWordCount in [1, 2] { 96 | let zeroWords = [Word](repeating: 0, count: zeroWordCount) 97 | let zeroWordsBitWidth = zeroWordCount * Word.bitWidth 98 | 99 | for (power, value) in allPositivePowersOf2(type: Word.self) { 100 | let words = zeroWords + [value] 101 | let heap = BigIntPrototype(isNegative: false, words: words) 102 | let bigInt = heap.create() 103 | 104 | let expected = power + correction + zeroWordsBitWidth 105 | XCTAssertEqual(bigInt.bitWidth, expected, "\(heap)") 106 | } 107 | } 108 | } 109 | 110 | // func test_bitWidth_multipleWords_negativePowersOf2() { 111 | // let correction = BitWidthTestCases.negativePowersOf2Correction 112 | // 113 | // for zeroWordCount in [1, 2] { 114 | // let zeroWords = [Word](repeating: 0, count: zeroWordCount) 115 | // let zeroWordsBitWidth = zeroWordCount * Word.bitWidth 116 | // 117 | // for (power, value) in allPositivePowersOf2(type: Word.self) { 118 | // let words = zeroWords + [value] 119 | // let heap = BigIntPrototype(isNegative: true, words: words) 120 | // let bigInt = heap.create() 121 | // 122 | // let expected = power + correction + zeroWordsBitWidth 123 | // XCTAssertEqual(bigInt.bitWidth, expected, "\(heap)") 124 | // } 125 | // } 126 | // } 127 | 128 | // MARK: - Trailing zero bit count 129 | 130 | func test_trailingZeroBitCount_zero() { 131 | let zero = BigInt(0) 132 | XCTAssertEqual(zero.trailingZeroBitCount, 0) 133 | } 134 | 135 | func test_trailingZeroBitCount_int() { 136 | for raw in generateIntValues(countButNotReally: 100) { 137 | if raw == 0 { 138 | continue 139 | } 140 | 141 | let int = BigInt(raw) 142 | let result = int.trailingZeroBitCount 143 | 144 | let expected = raw.trailingZeroBitCount 145 | XCTAssertEqual(result, expected) 146 | } 147 | } 148 | 149 | func test_trailingZeroBitCount_heap_nonZeroFirstWord() { 150 | for p in generateBigIntValues(countButNotReally: 100, maxWordCount: 3) { 151 | if p.isZero { 152 | continue 153 | } 154 | 155 | // We have separate test for numbers that have '0' last word 156 | if p.words[0] == 0 { 157 | continue 158 | } 159 | 160 | let int = p.create() 161 | let result = int.trailingZeroBitCount 162 | 163 | let expected = p.words[0].trailingZeroBitCount 164 | XCTAssertEqual(result, expected) 165 | } 166 | } 167 | 168 | func test_trailingZeroBitCount_heap_zeroFirstWord() { 169 | for p in generateBigIntValues(countButNotReally: 100, maxWordCount: 3) { 170 | if p.isZero { 171 | continue 172 | } 173 | 174 | guard p.words.count > 1 else { 175 | continue 176 | } 177 | 178 | var words = p.words 179 | words[0] = 0 180 | 181 | let heap = BigIntPrototype(isNegative: p.isNegative, words: words) 182 | let int = heap.create() 183 | let result = int.trailingZeroBitCount 184 | 185 | let expected = Word.bitWidth + p.words[1].trailingZeroBitCount 186 | XCTAssertEqual(result, expected) 187 | } 188 | } 189 | 190 | // MARK: - Magnitude 191 | 192 | func test_magnitude_int() { 193 | for raw in generateIntValues(countButNotReally: 100) { 194 | let int = BigInt(raw) 195 | let magnitude = int.magnitude 196 | 197 | let expected = raw.magnitude 198 | XCTAssert(magnitude == expected, "\(raw)") 199 | } 200 | } 201 | 202 | func test_magnitude_heap() { 203 | for p in generateBigIntValues(countButNotReally: 100) { 204 | if p.isZero { 205 | continue 206 | } 207 | 208 | let positiveHeap = BigIntPrototype(isNegative: false, words: p.words) 209 | let positive = positiveHeap.create() 210 | 211 | let negativeHeap = BigIntPrototype(isNegative: true, words: p.words) 212 | let negative = negativeHeap.create() 213 | 214 | XCTAssertEqual(positive.magnitude, negative.magnitude) 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Tests/BigIntTests/WordTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WordTests.swift 3 | // BigInt 4 | // 5 | // Created by Károly Lőrentey on 2017-7-26. 6 | // Copyright © 2017 Károly Lőrentey. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import BigInt 11 | 12 | // TODO: Return to `where Word.Magnitude == Word` when SR-13491 is resolved 13 | struct TestDivision { 14 | static func testDivision(_ u: (high: Word, low: Word.Magnitude), _ v: Word) { 15 | let (div, mod) = v.fastDividingFullWidth(u) 16 | var (ph, pl) = div.multipliedFullWidth(by: v) 17 | let (s, o) = pl.addingReportingOverflow((mod as! Word.Magnitude)) 18 | pl = s 19 | if o { ph += Word(1) } 20 | 21 | if mod >= v { 22 | XCTFail("For u = \(u), v = \(v): u mod v = \(mod), which is greater than v") 23 | } 24 | 25 | func message() -> String { 26 | let uhs = String(u.high, radix: 16) 27 | let uls = String(u.low, radix: 16) 28 | let vs = String(v, radix: 16) 29 | let divs = String(div, radix: 16) 30 | let mods = String(mod, radix: 16) 31 | let phs = String(ph, radix: 16) 32 | let pls = String(pl, radix: 16) 33 | return "(\(uhs),\(uls)) / \(vs) = (\(divs), \(mods)), but div * v + mod = (\(phs),\(pls))" 34 | } 35 | XCTAssertEqual(ph, u.high, message()) 36 | XCTAssertEqual(pl, u.low, message()) 37 | } 38 | 39 | static func test() { 40 | testDivision((0, 0), 2) 41 | testDivision((0, 1), 2) 42 | testDivision((1, 0), 2) 43 | testDivision((8, 0), 136) 44 | testDivision((128, 0), 136) 45 | testDivision((2, 0), 35) 46 | testDivision((7, 12), 19) 47 | } 48 | } 49 | 50 | class WordTests: XCTestCase { 51 | func testFullDivide() { 52 | TestDivision.test() 53 | TestDivision.test() 54 | TestDivision.test() 55 | TestDivision.test() 56 | TestDivision.test() 57 | 58 | #if false 59 | typealias Word = UInt8 60 | for v in 1 ... Word.max { 61 | for u1 in 0 ..< v { 62 | for u0 in 0 ..< Word.max { 63 | TestDivision.testDivision((u1, u0), v) 64 | } 65 | } 66 | } 67 | #endif 68 | } 69 | 70 | func testConversion() { 71 | enum Direction { 72 | case unitsToWords 73 | case wordsToUnits 74 | case both 75 | } 76 | func test 77 | (direction: Direction = .both, 78 | words: [Word], of wtype: Word.Type = Word.self, 79 | units: [Unit], of utype: Unit.Type = Unit.self, 80 | file: StaticString = #file, line: UInt = #line) { 81 | switch direction { 82 | case .wordsToUnits, .both: 83 | let actualUnits = [Unit](Units(of: Unit.self, words)) 84 | XCTAssertEqual(actualUnits, units, "words -> units", file: file, line: line) 85 | default: 86 | break 87 | } 88 | switch direction { 89 | case .unitsToWords, .both: 90 | var it = units.makeIterator() 91 | let actualWords = [Word](count: units.count, generator: { () -> Unit? in it.next() }) 92 | XCTAssertEqual(actualWords, words, "units -> words", file: file, line: line) 93 | default: 94 | break 95 | } 96 | } 97 | 98 | 99 | test(words: [], of: UInt8.self, 100 | units: [], of: UInt8.self) 101 | test(words: [0x01], of: UInt8.self, 102 | units: [0x01], of: UInt8.self) 103 | test(words: [0x01, 0x02], of: UInt8.self, 104 | units: [0x02, 0x01], of: UInt8.self) 105 | 106 | test(words: [], of: UInt8.self, 107 | units: [], of: UInt16.self) 108 | test(direction: .unitsToWords, 109 | words: [0x01, 0x00], of: UInt8.self, 110 | units: [0x0001], of: UInt16.self) 111 | test(direction: .wordsToUnits, 112 | words: [0x01], of: UInt8.self, 113 | units: [0x0001], of: UInt16.self) 114 | test(words: [0x01, 0x02], of: UInt8.self, 115 | units: [0x0201], of: UInt16.self) 116 | test(direction: .wordsToUnits, 117 | words: [0x01, 0x02, 0x03], of: UInt8.self, 118 | units: [0x0003, 0x0201], of: UInt16.self) 119 | test(direction: .unitsToWords, 120 | words: [0x01, 0x02, 0x03, 0x00], of: UInt8.self, 121 | units: [0x0003, 0x0201], of: UInt16.self) 122 | 123 | test(words: [], of: UInt16.self, 124 | units: [], of: UInt8.self) 125 | test(words: [0x1234], of: UInt16.self, 126 | units: [0x12, 0x34], of: UInt8.self) 127 | test(words: [0x5678, 0x1234], of: UInt16.self, 128 | units: [0x12, 0x34, 0x56, 0x78], of: UInt8.self) 129 | test(direction: .unitsToWords, 130 | words: [0x789A, 0x3456, 0x12], of: UInt16.self, 131 | units: [0x12, 0x34, 0x56, 0x78, 0x9A], of: UInt8.self) 132 | test(direction: .wordsToUnits, 133 | words: [0x789A, 0x3456, 0x12], of: UInt16.self, 134 | units: [0x00, 0x12, 0x34, 0x56, 0x78, 0x9A], of: UInt8.self) 135 | } 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /docs/Extensions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Extensions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | BigInt Docs 25 | 26 | (85% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 92 |
93 | 94 |
95 |
96 |

Extensions

97 |

The following extensions are available globally.

98 | 99 |
100 |
101 | 102 |
103 |
104 |
105 |
    106 |
  • 107 |
    108 | 109 | 110 | 111 | BinaryFloatingPoint 112 | 113 |
    114 |
    115 |
    116 |
    117 |
    118 |
    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    extension BinaryFloatingPoint where RawExponent: FixedWidthInteger, RawSignificand: FixedWidthInteger
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | String 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    extension String
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 165 |
166 |
167 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/Structs/BigInt/Sign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sign Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | BigInt Docs 25 | 26 | (85% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 92 |
93 | 94 |
95 |
96 |

Sign

97 |
98 |
99 | 100 |
public enum Sign
101 | 102 |
103 |
104 |

Undocumented

105 | 106 |
107 | Show on GitHub 108 |
109 |
110 |
111 | 112 |
113 |
114 |
115 |
    116 |
  • 117 |
    118 | 119 | 120 | 121 | plus 122 | 123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |

    Undocumented

    130 | 131 |
    132 |
    133 |

    Declaration

    134 |
    135 |

    Swift

    136 |
    case plus
    137 | 138 |
    139 |
    140 |
    141 | Show on GitHub 142 |
    143 |
    144 |
    145 |
  • 146 |
  • 147 |
    148 | 149 | 150 | 151 | minus 152 | 153 |
    154 |
    155 |
    156 |
    157 |
    158 |
    159 |

    Undocumented

    160 | 161 |
    162 |
    163 |

    Declaration

    164 |
    165 |

    Swift

    166 |
    case minus
    167 | 168 |
    169 |
    170 |
    171 | Show on GitHub 172 |
    173 |
    174 |
    175 |
  • 176 |
177 |
178 |
179 |
180 | 181 |
182 |
183 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 85% 23 | 24 | 25 | 85% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | /* Credit to https://gist.github.com/wataru420/2048287 */ 6 | .highlight .c { 7 | color: #999988; 8 | font-style: italic; } 9 | 10 | .highlight .err { 11 | color: #a61717; 12 | background-color: #e3d2d2; } 13 | 14 | .highlight .k { 15 | color: #000000; 16 | font-weight: bold; } 17 | 18 | .highlight .o { 19 | color: #000000; 20 | font-weight: bold; } 21 | 22 | .highlight .cm { 23 | color: #999988; 24 | font-style: italic; } 25 | 26 | .highlight .cp { 27 | color: #999999; 28 | font-weight: bold; } 29 | 30 | .highlight .c1 { 31 | color: #999988; 32 | font-style: italic; } 33 | 34 | .highlight .cs { 35 | color: #999999; 36 | font-weight: bold; 37 | font-style: italic; } 38 | 39 | .highlight .gd { 40 | color: #000000; 41 | background-color: #ffdddd; } 42 | 43 | .highlight .gd .x { 44 | color: #000000; 45 | background-color: #ffaaaa; } 46 | 47 | .highlight .ge { 48 | color: #000000; 49 | font-style: italic; } 50 | 51 | .highlight .gr { 52 | color: #aa0000; } 53 | 54 | .highlight .gh { 55 | color: #999999; } 56 | 57 | .highlight .gi { 58 | color: #000000; 59 | background-color: #ddffdd; } 60 | 61 | .highlight .gi .x { 62 | color: #000000; 63 | background-color: #aaffaa; } 64 | 65 | .highlight .go { 66 | color: #888888; } 67 | 68 | .highlight .gp { 69 | color: #555555; } 70 | 71 | .highlight .gs { 72 | font-weight: bold; } 73 | 74 | .highlight .gu { 75 | color: #aaaaaa; } 76 | 77 | .highlight .gt { 78 | color: #aa0000; } 79 | 80 | .highlight .kc { 81 | color: #000000; 82 | font-weight: bold; } 83 | 84 | .highlight .kd { 85 | color: #000000; 86 | font-weight: bold; } 87 | 88 | .highlight .kp { 89 | color: #000000; 90 | font-weight: bold; } 91 | 92 | .highlight .kr { 93 | color: #000000; 94 | font-weight: bold; } 95 | 96 | .highlight .kt { 97 | color: #445588; } 98 | 99 | .highlight .m { 100 | color: #009999; } 101 | 102 | .highlight .s { 103 | color: #d14; } 104 | 105 | .highlight .na { 106 | color: #008080; } 107 | 108 | .highlight .nb { 109 | color: #0086B3; } 110 | 111 | .highlight .nc { 112 | color: #445588; 113 | font-weight: bold; } 114 | 115 | .highlight .no { 116 | color: #008080; } 117 | 118 | .highlight .ni { 119 | color: #800080; } 120 | 121 | .highlight .ne { 122 | color: #990000; 123 | font-weight: bold; } 124 | 125 | .highlight .nf { 126 | color: #990000; } 127 | 128 | .highlight .nn { 129 | color: #555555; } 130 | 131 | .highlight .nt { 132 | color: #000080; } 133 | 134 | .highlight .nv { 135 | color: #008080; } 136 | 137 | .highlight .ow { 138 | color: #000000; 139 | font-weight: bold; } 140 | 141 | .highlight .w { 142 | color: #bbbbbb; } 143 | 144 | .highlight .mf { 145 | color: #009999; } 146 | 147 | .highlight .mh { 148 | color: #009999; } 149 | 150 | .highlight .mi { 151 | color: #009999; } 152 | 153 | .highlight .mo { 154 | color: #009999; } 155 | 156 | .highlight .sb { 157 | color: #d14; } 158 | 159 | .highlight .sc { 160 | color: #d14; } 161 | 162 | .highlight .sd { 163 | color: #d14; } 164 | 165 | .highlight .s2 { 166 | color: #d14; } 167 | 168 | .highlight .se { 169 | color: #d14; } 170 | 171 | .highlight .sh { 172 | color: #d14; } 173 | 174 | .highlight .si { 175 | color: #d14; } 176 | 177 | .highlight .sx { 178 | color: #d14; } 179 | 180 | .highlight .sr { 181 | color: #009926; } 182 | 183 | .highlight .s1 { 184 | color: #d14; } 185 | 186 | .highlight .ss { 187 | color: #990073; } 188 | 189 | .highlight .bp { 190 | color: #999999; } 191 | 192 | .highlight .vc { 193 | color: #008080; } 194 | 195 | .highlight .vg { 196 | color: #008080; } 197 | 198 | .highlight .vi { 199 | color: #008080; } 200 | 201 | .highlight .il { 202 | color: #009999; } 203 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.bigint 7 | CFBundleName 8 | BigInt 9 | DocSetPlatformFamily 10 | bigint 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | DashDocSetFallbackURL 20 | https://attaswift.github.io/BigInt/reference/ 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/Extensions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Extensions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | BigInt Docs 25 | 26 | (85% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 92 |
93 | 94 |
95 |
96 |

Extensions

97 |

The following extensions are available globally.

98 | 99 |
100 |
101 | 102 |
103 |
104 |
105 |
    106 |
  • 107 |
    108 | 109 | 110 | 111 | BinaryFloatingPoint 112 | 113 |
    114 |
    115 |
    116 |
    117 |
    118 |
    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    extension BinaryFloatingPoint where RawExponent: FixedWidthInteger, RawSignificand: FixedWidthInteger
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | String 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    extension String
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 165 |
166 |
167 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/Structs/BigInt/Sign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sign Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | BigInt Docs 25 | 26 | (85% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 92 |
93 | 94 |
95 |
96 |

Sign

97 |
98 |
99 | 100 |
public enum Sign
101 | 102 |
103 |
104 |

Undocumented

105 | 106 |
107 | Show on GitHub 108 |
109 |
110 |
111 | 112 |
113 |
114 |
115 |
    116 |
  • 117 |
    118 | 119 | 120 | 121 | plus 122 | 123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |

    Undocumented

    130 | 131 |
    132 |
    133 |

    Declaration

    134 |
    135 |

    Swift

    136 |
    case plus
    137 | 138 |
    139 |
    140 |
    141 | Show on GitHub 142 |
    143 |
    144 |
    145 |
  • 146 |
  • 147 |
    148 | 149 | 150 | 151 | minus 152 | 153 |
    154 |
    155 |
    156 |
    157 |
    158 |
    159 |

    Undocumented

    160 | 161 |
    162 |
    163 |

    Declaration

    164 |
    165 |

    Swift

    166 |
    case minus
    167 | 168 |
    169 |
    170 |
    171 | Show on GitHub 172 |
    173 |
    174 |
    175 |
  • 176 |
177 |
178 |
179 |
180 | 181 |
182 |
183 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /*! Jazzy - https://github.com/realm/jazzy 2 | * Copyright Realm Inc. 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | /* Credit to https://gist.github.com/wataru420/2048287 */ 6 | .highlight .c { 7 | color: #999988; 8 | font-style: italic; } 9 | 10 | .highlight .err { 11 | color: #a61717; 12 | background-color: #e3d2d2; } 13 | 14 | .highlight .k { 15 | color: #000000; 16 | font-weight: bold; } 17 | 18 | .highlight .o { 19 | color: #000000; 20 | font-weight: bold; } 21 | 22 | .highlight .cm { 23 | color: #999988; 24 | font-style: italic; } 25 | 26 | .highlight .cp { 27 | color: #999999; 28 | font-weight: bold; } 29 | 30 | .highlight .c1 { 31 | color: #999988; 32 | font-style: italic; } 33 | 34 | .highlight .cs { 35 | color: #999999; 36 | font-weight: bold; 37 | font-style: italic; } 38 | 39 | .highlight .gd { 40 | color: #000000; 41 | background-color: #ffdddd; } 42 | 43 | .highlight .gd .x { 44 | color: #000000; 45 | background-color: #ffaaaa; } 46 | 47 | .highlight .ge { 48 | color: #000000; 49 | font-style: italic; } 50 | 51 | .highlight .gr { 52 | color: #aa0000; } 53 | 54 | .highlight .gh { 55 | color: #999999; } 56 | 57 | .highlight .gi { 58 | color: #000000; 59 | background-color: #ddffdd; } 60 | 61 | .highlight .gi .x { 62 | color: #000000; 63 | background-color: #aaffaa; } 64 | 65 | .highlight .go { 66 | color: #888888; } 67 | 68 | .highlight .gp { 69 | color: #555555; } 70 | 71 | .highlight .gs { 72 | font-weight: bold; } 73 | 74 | .highlight .gu { 75 | color: #aaaaaa; } 76 | 77 | .highlight .gt { 78 | color: #aa0000; } 79 | 80 | .highlight .kc { 81 | color: #000000; 82 | font-weight: bold; } 83 | 84 | .highlight .kd { 85 | color: #000000; 86 | font-weight: bold; } 87 | 88 | .highlight .kp { 89 | color: #000000; 90 | font-weight: bold; } 91 | 92 | .highlight .kr { 93 | color: #000000; 94 | font-weight: bold; } 95 | 96 | .highlight .kt { 97 | color: #445588; } 98 | 99 | .highlight .m { 100 | color: #009999; } 101 | 102 | .highlight .s { 103 | color: #d14; } 104 | 105 | .highlight .na { 106 | color: #008080; } 107 | 108 | .highlight .nb { 109 | color: #0086B3; } 110 | 111 | .highlight .nc { 112 | color: #445588; 113 | font-weight: bold; } 114 | 115 | .highlight .no { 116 | color: #008080; } 117 | 118 | .highlight .ni { 119 | color: #800080; } 120 | 121 | .highlight .ne { 122 | color: #990000; 123 | font-weight: bold; } 124 | 125 | .highlight .nf { 126 | color: #990000; } 127 | 128 | .highlight .nn { 129 | color: #555555; } 130 | 131 | .highlight .nt { 132 | color: #000080; } 133 | 134 | .highlight .nv { 135 | color: #008080; } 136 | 137 | .highlight .ow { 138 | color: #000000; 139 | font-weight: bold; } 140 | 141 | .highlight .w { 142 | color: #bbbbbb; } 143 | 144 | .highlight .mf { 145 | color: #009999; } 146 | 147 | .highlight .mh { 148 | color: #009999; } 149 | 150 | .highlight .mi { 151 | color: #009999; } 152 | 153 | .highlight .mo { 154 | color: #009999; } 155 | 156 | .highlight .sb { 157 | color: #d14; } 158 | 159 | .highlight .sc { 160 | color: #d14; } 161 | 162 | .highlight .sd { 163 | color: #d14; } 164 | 165 | .highlight .s2 { 166 | color: #d14; } 167 | 168 | .highlight .se { 169 | color: #d14; } 170 | 171 | .highlight .sh { 172 | color: #d14; } 173 | 174 | .highlight .si { 175 | color: #d14; } 176 | 177 | .highlight .sx { 178 | color: #d14; } 179 | 180 | .highlight .sr { 181 | color: #009926; } 182 | 183 | .highlight .s1 { 184 | color: #d14; } 185 | 186 | .highlight .ss { 187 | color: #990073; } 188 | 189 | .highlight .bp { 190 | color: #999999; } 191 | 192 | .highlight .vc { 193 | color: #008080; } 194 | 195 | .highlight .vg { 196 | color: #008080; } 197 | 198 | .highlight .vi { 199 | color: #008080; } 200 | 201 | .highlight .il { 202 | color: #009999; } 203 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.docset/Contents/Resources/Documents/img/spinner.gif -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/Documents/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /docs/docsets/BigInt.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/BigInt.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/docsets/BigInt.tgz -------------------------------------------------------------------------------- /docs/docsets/BigInt.xml: -------------------------------------------------------------------------------- 1 | https://attaswift.github.io/BigInt/reference/docsets/BigInt.tgz 2 | -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/docs/img/spinner.gif -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/runner/work/BigInt/BigInt/Sources/BigInt.swift", 5 | "line": 30, 6 | "symbol": "BigInt.Sign", 7 | "symbol_kind": "source.lang.swift.decl.enum", 8 | "warning": "undocumented" 9 | }, 10 | { 11 | "file": "/Users/runner/work/BigInt/BigInt/Sources/BigInt.swift", 12 | "line": 31, 13 | "symbol": "BigInt.Sign.plus", 14 | "symbol_kind": "source.lang.swift.decl.enumelement", 15 | "warning": "undocumented" 16 | }, 17 | { 18 | "file": "/Users/runner/work/BigInt/BigInt/Sources/BigInt.swift", 19 | "line": 32, 20 | "symbol": "BigInt.Sign.minus", 21 | "symbol_kind": "source.lang.swift.decl.enumelement", 22 | "warning": "undocumented" 23 | }, 24 | { 25 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 26 | "line": 50, 27 | "symbol": "BigInt.~(_:)", 28 | "symbol_kind": "source.lang.swift.decl.function.method.static", 29 | "warning": "undocumented" 30 | }, 31 | { 32 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 33 | "line": 59, 34 | "symbol": "BigInt.&(_:_:)", 35 | "symbol_kind": "source.lang.swift.decl.function.method.static", 36 | "warning": "undocumented" 37 | }, 38 | { 39 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 40 | "line": 76, 41 | "symbol": "BigInt.|(_:_:)", 42 | "symbol_kind": "source.lang.swift.decl.function.method.static", 43 | "warning": "undocumented" 44 | }, 45 | { 46 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 47 | "line": 93, 48 | "symbol": "BigInt.^(_:_:)", 49 | "symbol_kind": "source.lang.swift.decl.function.method.static", 50 | "warning": "undocumented" 51 | }, 52 | { 53 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 54 | "line": 110, 55 | "symbol": "BigInt.&=(_:_:)", 56 | "symbol_kind": "source.lang.swift.decl.function.method.static", 57 | "warning": "undocumented" 58 | }, 59 | { 60 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 61 | "line": 114, 62 | "symbol": "BigInt.|=(_:_:)", 63 | "symbol_kind": "source.lang.swift.decl.function.method.static", 64 | "warning": "undocumented" 65 | }, 66 | { 67 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Bitwise Ops.swift", 68 | "line": 118, 69 | "symbol": "BigInt.^=(_:_:)", 70 | "symbol_kind": "source.lang.swift.decl.function.method.static", 71 | "warning": "undocumented" 72 | }, 73 | { 74 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Floating Point Conversion.swift", 75 | "line": 45, 76 | "symbol": "BinaryFloatingPoint.init(_:)", 77 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 78 | "warning": "undocumented" 79 | }, 80 | { 81 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Floating Point Conversion.swift", 82 | "line": 70, 83 | "symbol": "BinaryFloatingPoint.init(_:)", 84 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 85 | "warning": "undocumented" 86 | }, 87 | { 88 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Integer Conversion.swift", 89 | "line": 42, 90 | "symbol": "BigInt.init()", 91 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 92 | "warning": "undocumented" 93 | }, 94 | { 95 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 96 | "line": 109, 97 | "symbol": "BigUInt.>>=(_:_:)", 98 | "symbol_kind": "source.lang.swift.decl.function.method.static", 99 | "warning": "undocumented" 100 | }, 101 | { 102 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 103 | "line": 121, 104 | "symbol": "BigUInt.<<=(_:_:)", 105 | "symbol_kind": "source.lang.swift.decl.function.method.static", 106 | "warning": "undocumented" 107 | }, 108 | { 109 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 110 | "line": 129, 111 | "symbol": "BigUInt.>>(_:_:)", 112 | "symbol_kind": "source.lang.swift.decl.function.method.static", 113 | "warning": "undocumented" 114 | }, 115 | { 116 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 117 | "line": 139, 118 | "symbol": "BigUInt.<<(_:_:)", 119 | "symbol_kind": "source.lang.swift.decl.function.method.static", 120 | "warning": "undocumented" 121 | }, 122 | { 123 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 124 | "line": 168, 125 | "symbol": "BigInt.&<<(_:_:)", 126 | "symbol_kind": "source.lang.swift.decl.function.method.static", 127 | "warning": "undocumented" 128 | }, 129 | { 130 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 131 | "line": 172, 132 | "symbol": "BigInt.&<<=(_:_:)", 133 | "symbol_kind": "source.lang.swift.decl.function.method.static", 134 | "warning": "undocumented" 135 | }, 136 | { 137 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 138 | "line": 176, 139 | "symbol": "BigInt.&>>(_:_:)", 140 | "symbol_kind": "source.lang.swift.decl.function.method.static", 141 | "warning": "undocumented" 142 | }, 143 | { 144 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 145 | "line": 180, 146 | "symbol": "BigInt.&>>=(_:_:)", 147 | "symbol_kind": "source.lang.swift.decl.function.method.static", 148 | "warning": "undocumented" 149 | }, 150 | { 151 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 152 | "line": 184, 153 | "symbol": "BigInt.<<(_:_:)", 154 | "symbol_kind": "source.lang.swift.decl.function.method.static", 155 | "warning": "undocumented" 156 | }, 157 | { 158 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 159 | "line": 189, 160 | "symbol": "BigInt.<<=(_:_:)", 161 | "symbol_kind": "source.lang.swift.decl.function.method.static", 162 | "warning": "undocumented" 163 | }, 164 | { 165 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 166 | "line": 198, 167 | "symbol": "BigInt.>>(_:_:)", 168 | "symbol_kind": "source.lang.swift.decl.function.method.static", 169 | "warning": "undocumented" 170 | }, 171 | { 172 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Shifts.swift", 173 | "line": 203, 174 | "symbol": "BigInt.>>=(_:_:)", 175 | "symbol_kind": "source.lang.swift.decl.function.method.static", 176 | "warning": "undocumented" 177 | }, 178 | { 179 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Subtraction.swift", 180 | "line": 157, 181 | "symbol": "BigInt.negate()", 182 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 183 | "warning": "undocumented" 184 | }, 185 | { 186 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 187 | "line": 24, 188 | "symbol": "BigUInt.subscript(bitAt:)", 189 | "symbol_kind": "source.lang.swift.decl.function.subscript", 190 | "warning": "undocumented" 191 | }, 192 | { 193 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 194 | "line": 78, 195 | "symbol": "BigInt.bitWidth", 196 | "symbol_kind": "source.lang.swift.decl.var.instance", 197 | "warning": "undocumented" 198 | }, 199 | { 200 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 201 | "line": 83, 202 | "symbol": "BigInt.trailingZeroBitCount", 203 | "symbol_kind": "source.lang.swift.decl.var.instance", 204 | "warning": "undocumented" 205 | }, 206 | { 207 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 208 | "line": 105, 209 | "symbol": "BigUInt.init(words:)", 210 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 211 | "warning": "undocumented" 212 | }, 213 | { 214 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 215 | "line": 188, 216 | "symbol": "BigInt.words", 217 | "symbol_kind": "source.lang.swift.decl.var.instance", 218 | "warning": "undocumented" 219 | }, 220 | { 221 | "file": "/Users/runner/work/BigInt/BigInt/Sources/Words and Bits.swift", 222 | "line": 192, 223 | "symbol": "BigInt.init(words:)", 224 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 225 | "warning": "undocumented" 226 | } 227 | ], 228 | "source_directory": "/Users/runner/work/BigInt/BigInt" 229 | } -------------------------------------------------------------------------------- /images/BigInt.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/images/BigInt.sketch -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attaswift/BigInt/99c4b9fb0f52dc9182aee106b07c3d205583b98c/images/banner.png --------------------------------------------------------------------------------