├── .github ├── dependabot.yml └── workflows │ ├── doc.yaml │ └── test.yaml ├── .gitignore ├── bigints.nimble ├── examples ├── elliptic.nim ├── nim.cfg ├── pidigits.nim ├── pollard_p_minus_1.nim ├── pollard_rho.nim ├── rc_combperm.nim ├── rc_godtheinteger.nim ├── rc_godtheinteger2.nim ├── rc_hammingnumbers.nim ├── rc_integersequence.nim ├── rc_leftfactorials.nim ├── rc_paraffins.nim ├── rc_pow.nim └── rc_sum35.nim ├── license.txt ├── readme.md ├── src ├── bigints.nim └── bigints │ ├── private │ └── literals.nim │ └── random.nim └── tests ├── nim.cfg ├── tbigints.nim ├── tbugs.nim ├── tliterals.nim └── trandom.nim /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/doc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: docs 3 | 4 | # yamllint disable-line rule:truthy 5 | on: 6 | push: 7 | branches: 8 | - master 9 | env: 10 | nim-src: src/${{ github.event.repository.name }}.nim 11 | deploy-dir: .gh-pages 12 | jobs: 13 | docs: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: jiro4989/setup-nim-action@v2 18 | with: 19 | nim-version: 'devel' 20 | - run: nimble install -Y 21 | - run: nimble doc --index:on --project --git.url:https://github.com/${{ github.repository }} --git.commit:master --out:${{ env.deploy-dir }} ${{ env.nim-src }} 22 | - name: "Copy to index.html" 23 | run: cp ${{ env.deploy-dir }}/${{ github.event.repository.name }}.html ${{ env.deploy-dir }}/index.html 24 | - name: Deploy documents 25 | uses: peaceiris/actions-gh-pages@v4 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | publish_dir: ${{ env.deploy-dir }} 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: test 3 | 4 | # yamllint disable-line rule:truthy 5 | on: 6 | - push 7 | - pull_request 8 | 9 | jobs: 10 | before: 11 | runs-on: ubuntu-latest 12 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 13 | steps: 14 | - run: echo "commit message doesn't contain '[skip ci]'" 15 | 16 | test: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | nim-version: 21 | - '1.4.8' 22 | - '1.6.12' 23 | - 'devel' 24 | needs: before 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: jiro4989/setup-nim-action@v2 28 | with: 29 | nim-version: ${{ matrix.nim-version }} 30 | - run: nimble install -y 31 | - run: nimble test 32 | - run: nimble checkExamples 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !*.* 4 | nimcache/ 5 | *.swp 6 | *.exe 7 | testresults/ 8 | -------------------------------------------------------------------------------- /bigints.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "1.1.0" 4 | author = "Dennis Felsing; narimiran" 5 | description = "Arbitrary-precision integers implemented in pure Nim" 6 | license = "MIT" 7 | 8 | srcDir = "src" 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 1.4.0" 13 | 14 | task test, "Test bigints": 15 | for backend in ["c", "cpp"]: 16 | echo "testing " & backend & " backend" 17 | for gc in ["refc", "arc", "orc"]: 18 | echo " using " & gc & " GC" 19 | for file in ["tbigints.nim", "tbugs.nim", "trandom.nim"]: 20 | exec "nim r --hints:off --experimental:strictFuncs --backend:" & backend & " --gc:" & gc & " tests/" & file 21 | exec "nim doc --hints:off --backend:" & backend & " --gc:" & gc & " src/bigints.nim" 22 | 23 | task checkExamples, "Check examples": 24 | echo "checking examples" 25 | for example in listFiles("examples"): 26 | if example.endsWith(".nim"): 27 | exec "nim check --hints:off " & example 28 | -------------------------------------------------------------------------------- /examples/elliptic.nim: -------------------------------------------------------------------------------- 1 | # By Cyther606: https://forum.nim-lang.org/t/522 2 | # Adapted from: https://github.com/wobine/blackboard101/blob/master/EllipticCurvesPart4-PrivateKeyToPublicKey.py 3 | import bigints 4 | import std/[math, strutils] 5 | 6 | const 7 | one = 1.initBigInt 8 | two = 2.initBigInt 9 | zero = 0.initBigInt 10 | 11 | proc `^`(base: int; exp: int): BigInt = pow(base.initBigInt, exp) 12 | 13 | # Specs of the Bitcoin's curve - secp256k1 14 | let 15 | primeCurve: BigInt = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - one 16 | numberPoints = initBigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) 17 | Acurve = zero # with Bcurve = 7, coefficients in the elliptic curve equation y^2 = x^3 + Acurve * x + Bcurve 18 | Gx = initBigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240") 19 | Gy = initBigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424") 20 | Gpoint = (Gx, Gy) 21 | privKey = initBigInt("A0DC65FFCA799873CBEA0AC274015B9526505DAAAED385155425F7337704883E", 16) 22 | 23 | proc ecAdd(a: tuple, b: tuple): (BigInt, BigInt) = 24 | let 25 | lamAdd = ((b[1] - a[1]) * invmod((b[0] - a[0]), primeCurve)) mod primeCurve 26 | x = (lamAdd * lamAdd - a[0] - b[0]) mod primeCurve 27 | y = (lamAdd * (a[0] - x) - a[1]) mod primeCurve 28 | result = (x, y) 29 | 30 | proc ecDouble(a: tuple): (BigInt, BigInt) = 31 | var 32 | lam = ((3.initBigInt * a[0] * a[0] + Acurve) * invmod(2.initBigInt * a[1], primeCurve)) 33 | x = ((lam * lam) - (2.initBigInt * a[0])) mod primeCurve 34 | y = (lam * (a[0] - x) - a[1]) mod primeCurve 35 | lam = lam mod primeCurve 36 | result = (x, y) 37 | 38 | proc ecMultiply(genPoint: tuple, scalarHex: BigInt): (BigInt, BigInt) = 39 | if scalarHex == zero or scalarHex >= numberPoints: 40 | raise newException(Exception, "Invalid Scalar/Private Key") 41 | var 42 | scalarBin = scalarHex.toString(base = 2) 43 | q = genPoint 44 | for i in 1 ..< scalarBin.len: 45 | q = ecDouble(q) 46 | if scalarBin[i] == '1': 47 | q = ecAdd(q, genPoint) 48 | result = q 49 | 50 | proc main() = 51 | let publicKey = ecMultiply(Gpoint, privKey) 52 | 53 | echo "" 54 | echo "******* Public Key Generation *********" 55 | echo "" 56 | echo "the private key: " 57 | echo privKey 58 | echo "" 59 | echo "the uncompressed public key (not address):" 60 | echo publicKey 61 | echo "" 62 | echo "the uncompressed public key (HEX):" 63 | echo "04", publicKey[0].toString(base = 16).align(64, '0'), publicKey[1].toString(base = 16).align(64, '0') 64 | echo "" 65 | echo "the official Public Key - compressed:" 66 | echo if publicKey[1] mod two == one: "03" & publicKey[0].toString(base = 16).align(64, '0') 67 | else: "02" & publicKey[0].toString(base = 16).align(64, '0') 68 | 69 | main() 70 | -------------------------------------------------------------------------------- /examples/nim.cfg: -------------------------------------------------------------------------------- 1 | path = "$projectPath/../src" 2 | -------------------------------------------------------------------------------- /examples/pidigits.nim: -------------------------------------------------------------------------------- 1 | # This program prints as much pi digits as the user indicates 2 | # with the first command line argument 3 | # This program is an extension of the solution for https://rosettacode.org/wiki/Pi 4 | # translated from former website http://benchmarksgame.alioth.debian.org 5 | 6 | import std/[os, strutils, options] 7 | import bigints 8 | 9 | const 10 | zero = 0.initBigInt 11 | one = 1.initBigInt 12 | two = 2.initBigInt 13 | ten = 10.initBigInt 14 | let 15 | mask = (one shl 32) - one 16 | 17 | var 18 | tmp1, tmp2, tmp3, acc, k = zero 19 | den, num, k2 = one 20 | 21 | proc extractDigit(): int32 = 22 | if num > acc: 23 | return -1 24 | 25 | tmp3 = num shl 1 26 | tmp3 += num 27 | tmp3 += acc 28 | tmp2 = tmp3 mod den 29 | tmp1 = tmp3 div den 30 | tmp2 += num 31 | 32 | if tmp2 >= den: 33 | return -1 34 | 35 | result = get(toInt[int32](tmp1 and mask)) 36 | 37 | proc eliminateDigit(d: int32) = 38 | acc -= den * d.initBigInt 39 | acc *= ten 40 | num *= ten 41 | 42 | proc nextTerm() = 43 | k += one 44 | k2 += two 45 | tmp1 = num shl 1 46 | acc += tmp1 47 | acc *= k2 48 | den *= k2 49 | num *= k 50 | 51 | proc findPiDigit(): int32 = 52 | result = -1 53 | while result < 0: 54 | nextTerm() 55 | result = extractDigit() 56 | 57 | var i = 0 58 | if paramCount() == 0: 59 | # prints an infinite amount of pi digits 60 | while true: 61 | var d: int32 = findPiDigit() 62 | stdout.write chr(ord('0') + d) 63 | inc i 64 | if i == 40: 65 | echo "" 66 | i = 0 67 | eliminateDigit(d) 68 | 69 | let n = parseInt(paramStr(1)) 70 | 71 | if n <= 0: 72 | quit("The number you entered is negative. Please specify a strictly positive number") 73 | 74 | while i < n: 75 | var d: int32 = findPiDigit() 76 | stdout.write(chr(ord('0') + d)) 77 | inc(i) 78 | if i mod 40 == 0: 79 | echo "\t:", i 80 | eliminateDigit(d) 81 | -------------------------------------------------------------------------------- /examples/pollard_p_minus_1.nim: -------------------------------------------------------------------------------- 1 | ## Pollard's p-1 2 | ## 3 | ## This file illustrates how to find a factor of an integer using 4 | ## [Pollard's p-1 algorithm](https://en.wikipedia.org/wiki/Pollard%27s_p_%E2%88%92_1_algorithm). 5 | 6 | import bigints 7 | import std/options 8 | import std/strformat 9 | 10 | 11 | func pollardPMinus1( 12 | n: BigInt, 13 | searchLimit: BigInt, 14 | powerBase: BigInt = 2.initBigInt): Option[BigInt] = 15 | ## Performs Pollard's p-1 algorithm to find a non-trivial factor of `n`. 16 | var curPow = powerBase mod n 17 | 18 | for k in 1.initBigInt .. searchLimit: 19 | curPow = curPow.powmod(k, n) 20 | let divisor = gcd(curPow-1.initBigInt, n) 21 | if divisor != 1.initBigInt and divisor != n: 22 | return some(divisor) 23 | 24 | none(BigInt) 25 | 26 | 27 | proc main() = 28 | const someNum = "52541208898777".initBigInt 29 | let result = pollardPMinus1(someNum, "1000000".initBigInt) 30 | if result.isSome(): 31 | let factor = result.get() 32 | echo fmt"{factor} is a factor of {someNum}" 33 | assert someNum mod factor == 0.initBigInt 34 | else: 35 | echo fmt"could not find a factor of {someNum}" 36 | 37 | 38 | main() 39 | -------------------------------------------------------------------------------- /examples/pollard_rho.nim: -------------------------------------------------------------------------------- 1 | ## Pollard's rho algorithm 2 | ## 3 | ## This file illustrates how to find a factor of an integer using 4 | ## [Pollard's rho algorithm](https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm). 5 | 6 | import bigints 7 | import std/options 8 | import std/strformat 9 | 10 | 11 | func pollardRho( 12 | n: BigInt, 13 | polynomial: proc(x: BigInt): BigInt {.noSideEffect.}, 14 | initialValue: BigInt = 2.initBigInt): Option[BigInt] = 15 | ## Performs Pollard's rho algorithm to find a non-trivial factor of `n`. 16 | func polynomialMod(x: BigInt): BigInt = 17 | polynomial(x) mod n 18 | 19 | var 20 | turtle = initialValue 21 | hare = initialValue 22 | divisor = 1.initBigInt 23 | 24 | while divisor == 1.initBigInt: 25 | turtle = polynomialMod(turtle) 26 | hare = polynomialMod(polynomialMod(hare)) 27 | divisor = gcd(turtle - hare, n) 28 | 29 | if divisor != n: 30 | some(divisor) 31 | else: 32 | none(BigInt) 33 | 34 | 35 | func somePolynomial(x: BigInt): BigInt = 36 | x * x + 1.initBigInt 37 | 38 | 39 | proc main() = 40 | const someNum = "44077431694086786329".initBigInt 41 | let result = pollardRho(someNum, somePolynomial) 42 | if result.isSome(): 43 | let factor = result.get() 44 | echo fmt"{factor} is a factor of {someNum}" 45 | assert someNum mod factor == 0.initBigInt 46 | else: 47 | echo fmt"could not find a factor of {someNum}" 48 | 49 | 50 | main() 51 | -------------------------------------------------------------------------------- /examples/rc_combperm.nim: -------------------------------------------------------------------------------- 1 | # Solution for https://rosettacode.org/wiki/Combinations_and_permutations 2 | import bigints 3 | 4 | proc perm(n, k: int32): BigInt = 5 | result = initBigInt(1) 6 | var 7 | k = initBigInt(n - k) 8 | n = initBigInt(n) 9 | while n > k: 10 | result *= n 11 | dec n 12 | 13 | proc comb(n, k: int32): BigInt = 14 | result = perm(n, k) 15 | var k = initBigInt(k) 16 | while k > 0.initBigInt: 17 | result = result div k 18 | dec k 19 | 20 | echo "P(1000, 969) = ", perm(1000, 969) 21 | echo "C(1000, 969) = ", comb(1000, 969) 22 | -------------------------------------------------------------------------------- /examples/rc_godtheinteger.nim: -------------------------------------------------------------------------------- 1 | # Solution for https://rosettacode.org/wiki/9_billion_names_of_God_the_integer#Python 2 | import bigints 3 | 4 | var cache = @[@[1.initBigInt]] 5 | 6 | proc cumu(n: int): seq[BigInt] = 7 | for l in cache.len .. n: 8 | var r = @[0.initBigInt] 9 | for x in 1..l: 10 | r.add r[r.high] + cache[l-x][min(x, l-x)] 11 | cache.add r 12 | result = cache[n] 13 | 14 | proc row(n: int): seq[BigInt] = 15 | let r = cumu n 16 | result = @[] 17 | for i in 0 ..< n: 18 | result.add r[i+1] - r[i] 19 | 20 | echo "rows:" 21 | for x in 1..10: 22 | echo row x 23 | 24 | echo "sums:" 25 | # for 12345 this implementation is too slow, for a faster implementation see rc_godtheinteger2.nim 26 | for x in [23, 123, 1234]: 27 | let c = cumu(x) 28 | echo x, " ", c[c.high] 29 | -------------------------------------------------------------------------------- /examples/rc_godtheinteger2.nim: -------------------------------------------------------------------------------- 1 | # Solution for https://rosettacode.org/wiki/9_billion_names_of_God_the_integer#Python 2 | import bigints 3 | 4 | var p = @[1.initBigInt] 5 | 6 | proc partitions(n: int): BigInt = 7 | p.add 0.initBigInt 8 | 9 | for k in 1..n: 10 | var d = n - k * (3 * k - 1) div 2 11 | if d < 0: 12 | break 13 | 14 | if (k and 1) != 0: 15 | p[n] += p[d] 16 | else: 17 | p[n] -= p[d] 18 | 19 | d -= k 20 | if d < 0: 21 | break 22 | 23 | if (k and 1) != 0: 24 | p[n] += p[d] 25 | else: 26 | p[n] -= p[d] 27 | 28 | result = p[p.high] 29 | 30 | const ns = [23, 123, 1234, 12345] 31 | for i in 1 .. max(ns): 32 | let p = partitions(i) 33 | if i in ns: 34 | echo i,": ",p 35 | -------------------------------------------------------------------------------- /examples/rc_hammingnumbers.nim: -------------------------------------------------------------------------------- 1 | # Translation of https://rosettacode.org/wiki/Hamming_numbers#Another_implementation_of_same_approach 2 | import bigints 3 | 4 | const 5 | two = initBigInt(2) 6 | three = initBigInt(3) 7 | five = initBigInt(5) 8 | 9 | proc hamming(limit: int): BigInt = 10 | var 11 | h = newSeq[BigInt](limit) 12 | x2 = two 13 | x3 = three 14 | x5 = five 15 | i, j, k = 0 16 | for i in 0..h.high: h[i] = initBigInt(1) 17 | 18 | for n in 1 ..< limit: 19 | h[n] = min([x2, x3, x5]) 20 | if x2 == h[n]: 21 | inc i 22 | x2 = h[i] * two 23 | if x3 == h[n]: 24 | inc j 25 | x3 = h[j] * three 26 | if x5 == h[n]: 27 | inc k 28 | x5 = h[k] * five 29 | 30 | result = h[h.high] 31 | 32 | for i in 1 .. 20: 33 | stdout.write hamming(i), " " 34 | 35 | echo hamming(1691) 36 | echo hamming(1_000_000) 37 | -------------------------------------------------------------------------------- /examples/rc_integersequence.nim: -------------------------------------------------------------------------------- 1 | # This example includes an infinite loop that has to be interrupted by Ctrl+C 2 | import bigints 3 | 4 | const one = 1.initBigInt 5 | var i = 0.initBigInt 6 | while true: 7 | i += one 8 | echo i 9 | -------------------------------------------------------------------------------- /examples/rc_leftfactorials.nim: -------------------------------------------------------------------------------- 1 | import bigints 2 | 3 | const 4 | one = 1.initBigInt 5 | zero = 0.initBigInt 6 | 7 | iterator lfact: BigInt = 8 | yield zero 9 | var 10 | fact = one 11 | sum = zero 12 | n = one 13 | while true: 14 | sum += fact 15 | fact *= n 16 | n += one 17 | yield sum 18 | 19 | var i = 0 20 | for n in lfact(): 21 | if i == 0: 22 | echo "first 11:" 23 | if i == 20: 24 | echo "20 through 110 (inclusive) by tens:" 25 | if i == 1000: 26 | echo "Digits in 1,000 through 10,000 (inclusive) by thousands:" 27 | 28 | if i <= 10: 29 | echo i, ": ", n 30 | elif i <= 110 and i mod 10 == 0: 31 | echo i, ": ", n 32 | elif i >= 1000 and i <= 10_000 and i mod 1000 == 0: 33 | echo i, ": ", ($n).len 34 | elif i > 10_000: 35 | break 36 | inc i 37 | 38 | -------------------------------------------------------------------------------- /examples/rc_paraffins.nim: -------------------------------------------------------------------------------- 1 | # Solution for https://rosettacode.org/wiki/Paraffins 2 | import bigints 3 | 4 | const 5 | nMax: int32 = 250 6 | nBranches: int32 = 4 7 | 8 | const 9 | one = 1.initBigInt 10 | zero = 0.initBigInt 11 | 12 | var rooted, unrooted: array[nMax + 1, BigInt] 13 | rooted[0..1] = [one, one] 14 | unrooted[0..1] = [one, one] 15 | for i in 2 .. nMax: 16 | rooted[i] = zero 17 | unrooted[i] = zero 18 | 19 | proc choose(m: BigInt, k: int32): BigInt = 20 | result = m 21 | if k == 1: return 22 | for i in 1 ..< k: 23 | result = result * (m + i.initBigInt) div (i + 1).initBigInt 24 | 25 | proc tree(br, n, l, sum: int32, cnt: BigInt) = 26 | var s: int32 = 0 27 | for b in br + 1 .. nBranches: 28 | s = sum + (b - br) * n 29 | if s > nMax: return 30 | 31 | let c = choose(rooted[n], b - br) * cnt 32 | 33 | if l * 2 < s: unrooted[s] += c 34 | if b == nBranches: return 35 | rooted[s] += c 36 | for m in countdown(n-1, 1): 37 | tree b, m, l, s, c 38 | 39 | proc bicenter(s: int32) = 40 | var s = s 41 | if (s and 1) == 0: 42 | unrooted[s] += rooted[s div 2] * (rooted[s div 2] + 1.initBigInt) div 2.initBigInt 43 | 44 | for n in 1 .. nMax: 45 | tree 0, n, n, 1, 1.initBigInt 46 | n.bicenter 47 | echo n, ": ", unrooted[n] 48 | -------------------------------------------------------------------------------- /examples/rc_pow.nim: -------------------------------------------------------------------------------- 1 | # Solution for https://rosettacode.org/wiki/Arbitrary-precision_integers_(included) 2 | import bigints 3 | import std/math 4 | 5 | var x = 5.initBigInt.pow 4 ^ (3 ^ 2) 6 | var s = $x 7 | 8 | echo s[0..19] 9 | echo s[s.high - 19 .. s.high] 10 | echo s.len 11 | -------------------------------------------------------------------------------- /examples/rc_sum35.nim: -------------------------------------------------------------------------------- 1 | import bigints 2 | 3 | const 4 | one = 1.initBigInt 5 | two = 2.initBigInt 6 | ten = 10.initBigInt 7 | 8 | proc sumMults(first: int32, limit: BigInt): BigInt = 9 | var last = limit - one 10 | var first = first.initBigInt 11 | last -= last mod first 12 | (last div first) * (last + first) div two 13 | 14 | proc sum35(n: BigInt): BigInt = 15 | result = sumMults(3, n) 16 | result += sumMults(5, n) 17 | result -= sumMults(15, n) 18 | 19 | var x = one 20 | while x < "1000000000000000000000000000000".initBigInt: 21 | echo sum35 x 22 | x *= ten 23 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 Dennis Felsing 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Pure BigInts for Nim 2 | 3 | [![test](https://github.com/nim-lang/bigints/actions/workflows/test.yaml/badge.svg)](https://github.com/nim-lang/bigints/actions/workflows/test.yaml) 4 | 5 | This library provides a pure implementation for arbitrary precision integers in [Nim](https://nim-lang.org/). 6 | 7 | It can be installed through nimble with: 8 | 9 | ``` 10 | nimble install https://github.com/nim-lang/bigints 11 | ``` 12 | 13 | `bigints` provides a `BigInt` type and related operations with standard Nim syntax: 14 | 15 | - creation of `BigInt` from all standard integer types (`initBigInt`) 16 | - comparisons (`<`, `<=`, `==`) 17 | - addition, negation and subtraction (`+`, `-`, `+=` `-=`) 18 | - multiplication (`*`, `*=`) 19 | - bit shifts (`shr`, `shl`) 20 | - bitwise `not`, `and`, `or` and `xor` (behave as if negative numbers were represented in 2's complement) 21 | - integer division and modulo operation (`div`, `mod`) 22 | - conversion of `BigInt` from/to strings supporting bases from 2 to 36 (`initBigInt`, `$`) 23 | - iteration utilities (`inc`, `dec`, `countdown`, `countup`, `..`, `..<`) 24 | 25 | 26 | 27 | ## Current limitations and possible enhancements 28 | 29 | * not expected to work on 32 bit 30 | * arithmetic operations such as addition, multiplication and division are not optimized for performance (e.g. [Karatsuba multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) is not implemented) 31 | 32 | 33 | 34 | ## Documentation 35 | 36 | The documentation is available at https://nim-lang.github.io/bigints. 37 | -------------------------------------------------------------------------------- /src/bigints.nim: -------------------------------------------------------------------------------- 1 | ## Arbitrary precision integers. 2 | ## 3 | ## The bitwise operations behave as if negative numbers were represented in 2's complement. 4 | 5 | import std/[algorithm, bitops, math, options] 6 | 7 | type 8 | BigInt* = object 9 | ## An arbitrary precision integer. 10 | # Invariants for `a: BigInt`: 11 | # * if `a` is non-zero: `a.limbs[a.limbs.high] != 0` 12 | # * if `a` is zero: `a.limbs.len <= 1` 13 | limbs: seq[uint32] 14 | isNegative: bool 15 | 16 | 17 | # forward declarations 18 | func succ*(a: BigInt, b: int = 1): BigInt 19 | func inc*(a: var BigInt, b: int = 1) 20 | func dec*(a: var BigInt, b: int = 1) 21 | 22 | 23 | func normalize(a: var BigInt) = 24 | for i in countdown(a.limbs.high, 0): 25 | if a.limbs[i] > 0'u32: 26 | a.limbs.setLen(i+1) 27 | return 28 | a.limbs.setLen(1) 29 | 30 | func initBigInt*(vals: sink seq[uint32], isNegative = false): BigInt = 31 | ## Initializes a `BigInt` from a sequence of `uint32` values. 32 | runnableExamples: 33 | let a = @[10'u32, 2'u32].initBigInt 34 | let b = 10 + 2 shl 32 35 | assert $a == $b 36 | result.limbs = vals 37 | result.isNegative = isNegative 38 | normalize(result) 39 | 40 | func initBigInt*[T: int8|int16|int32](val: T): BigInt = 41 | if val < 0: 42 | result.limbs = @[(not val).uint32 + 1] # manual 2's complement (to avoid overflow) 43 | result.isNegative = true 44 | else: 45 | result.limbs = @[val.uint32] 46 | result.isNegative = false 47 | 48 | func initBigInt*[T: uint8|uint16|uint32](val: T): BigInt = 49 | result.limbs = @[val.uint32] 50 | 51 | func initBigInt*(val: int64): BigInt = 52 | var a = val.uint64 53 | if val < 0: 54 | a = not a + 1 # 2's complement 55 | result.isNegative = true 56 | if a > uint32.high: 57 | result.limbs = @[(a and uint32.high).uint32, (a shr 32).uint32] 58 | else: 59 | result.limbs = @[a.uint32] 60 | 61 | func initBigInt*(val: uint64): BigInt = 62 | if val > uint32.high: 63 | result.limbs = @[(val and uint32.high).uint32, (val shr 32).uint32] 64 | else: 65 | result.limbs = @[val.uint32] 66 | 67 | when sizeof(int) == 4: 68 | template initBigInt*(val: int): BigInt = initBigInt(val.int32) 69 | template initBigInt*(val: uint): BigInt = initBigInt(val.uint32) 70 | else: 71 | template initBigInt*(val: int): BigInt = initBigInt(val.int64) 72 | template initBigInt*(val: uint): BigInt = initBigInt(val.uint64) 73 | 74 | func initBigInt*(val: BigInt): BigInt = 75 | result = val 76 | 77 | const 78 | zero = initBigInt(0) 79 | one = initBigInt(1) 80 | 81 | func isZero(a: BigInt): bool {.inline.} = 82 | a.limbs.len == 0 or (a.limbs.len == 1 and a.limbs[0] == 0) 83 | 84 | func abs*(a: BigInt): BigInt = 85 | # Returns the absolute value of `a`. 86 | runnableExamples: 87 | assert abs(42.initBigInt) == 42.initBigInt 88 | assert abs(-12.initBigInt) == 12.initBigInt 89 | result = a 90 | result.isNegative = false 91 | 92 | func unsignedCmp(a: BigInt, b: uint32): int64 = 93 | # ignores the sign of `a` 94 | # `a` and `b` are assumed to not be zero 95 | result = int64(a.limbs.len) - 1 96 | if result != 0: return 97 | result = int64(a.limbs[0]) - int64(b) 98 | 99 | func unsignedCmp(a: uint32, b: BigInt): int64 = -unsignedCmp(b, a) 100 | 101 | func unsignedCmp(a, b: BigInt): int64 = 102 | # ignores the signs of `a` and `b` 103 | # `a` and `b` are assumed to not be zero 104 | result = int64(a.limbs.len) - int64(b.limbs.len) 105 | if result != 0: return 106 | for i in countdown(a.limbs.high, 0): 107 | result = int64(a.limbs[i]) - int64(b.limbs[i]) 108 | if result != 0: 109 | return 110 | 111 | func cmp(a, b: BigInt): int64 = 112 | ## Returns: 113 | ## * a value less than zero, if `a < b` 114 | ## * a value greater than zero, if `a > b` 115 | ## * zero, if `a == b` 116 | if a.isZero: 117 | if b.isZero: 118 | return 0 119 | elif b.isNegative: 120 | return 1 121 | else: 122 | return -1 123 | elif a.isNegative: 124 | if b.isZero or not b.isNegative: 125 | return -1 126 | else: 127 | return unsignedCmp(b, a) 128 | else: # a > 0 129 | if b.isZero or b.isNegative: 130 | return 1 131 | else: 132 | return unsignedCmp(a, b) 133 | 134 | func cmp(a: BigInt, b: int32): int64 = 135 | ## Returns: 136 | ## * a value less than zero, if `a < b` 137 | ## * a value greater than zero, if `a > b` 138 | ## * zero, if `a == b` 139 | if a.isZero: 140 | return -b.int64 141 | elif a.isNegative: 142 | if b < 0: 143 | return unsignedCmp((not b).uint32 + 1, a) 144 | else: 145 | return -1 146 | else: # a > 0 147 | if b <= 0: 148 | return 1 149 | else: 150 | return unsignedCmp(a, b.uint32) 151 | 152 | func cmp(a: int32, b: BigInt): int64 = -cmp(b, a) 153 | 154 | func `==`*(a, b: BigInt): bool = 155 | ## Compares if two `BigInt` numbers are equal. 156 | runnableExamples: 157 | let 158 | a = 5.initBigInt 159 | b = 3.initBigInt 160 | c = 2.initBigInt 161 | assert a == b + c 162 | assert b != c 163 | cmp(a, b) == 0 164 | 165 | func `<`*(a, b: BigInt): bool = 166 | runnableExamples: 167 | let 168 | a = 5.initBigInt 169 | b = 3.initBigInt 170 | c = 2.initBigInt 171 | assert b < a 172 | assert b > c 173 | cmp(a, b) < 0 174 | 175 | func `<=`*(a, b: BigInt): bool = 176 | runnableExamples: 177 | let 178 | a = 5.initBigInt 179 | b = 3.initBigInt 180 | c = 2.initBigInt 181 | assert a <= b + c 182 | assert c <= b 183 | cmp(a, b) <= 0 184 | 185 | func `==`(a: BigInt, b: int32): bool = cmp(a, b) == 0 186 | func `<`(a: BigInt, b: int32): bool = cmp(a, b) < 0 187 | func `<`(a: int32, b: BigInt): bool = cmp(a, b) < 0 188 | 189 | template addParts(toAdd) = 190 | tmp += toAdd 191 | a.limbs[i] = uint32(tmp and uint32.high) 192 | tmp = tmp shr 32 193 | 194 | func unsignedAdditionInt(a: var BigInt, b: BigInt, c: uint32) = 195 | let bl = b.limbs.len 196 | a.limbs.setLen(bl) 197 | 198 | var tmp: uint64 = uint64(c) 199 | for i in 0 ..< bl: 200 | addParts(uint64(b.limbs[i])) 201 | if tmp > 0'u64: 202 | a.limbs.add(uint32(tmp)) 203 | a.isNegative = false 204 | 205 | func unsignedAddition(a: var BigInt, b, c: BigInt) = 206 | let 207 | bl = b.limbs.len 208 | cl = c.limbs.len 209 | var m = min(bl, cl) 210 | a.limbs.setLen(max(bl, cl)) 211 | 212 | var tmp = 0'u64 213 | for i in 0 ..< m: 214 | addParts(uint64(b.limbs[i]) + uint64(c.limbs[i])) 215 | if bl < cl: 216 | for i in m ..< cl: 217 | addParts(uint64(c.limbs[i])) 218 | else: 219 | for i in m ..< bl: 220 | addParts(uint64(b.limbs[i])) 221 | if tmp > 0'u64: 222 | a.limbs.add(uint32(tmp)) 223 | a.isNegative = false 224 | 225 | func negate(a: var BigInt) = 226 | a.isNegative = not a.isNegative 227 | 228 | func `-`*(a: BigInt): BigInt = 229 | ## Unary minus for `BigInt`. 230 | runnableExamples: 231 | let 232 | a = 5.initBigInt 233 | b = -10.initBigInt 234 | assert (-a) == -5.initBigInt 235 | assert (-b) == 10.initBigInt 236 | result = a 237 | negate(result) 238 | 239 | template realUnsignedSubtractionInt(a: var BigInt, b: BigInt, c: uint32) = 240 | # b > c 241 | let bl = b.limbs.len 242 | a.limbs.setLen(bl) 243 | 244 | var tmp = int64(c) 245 | for i in 0 ..< bl: 246 | tmp = int64(uint32.high) + 1 + int64(b.limbs[i]) - tmp 247 | a.limbs[i] = uint32(tmp and int64(uint32.high)) 248 | tmp = 1 - (tmp shr 32) 249 | a.isNegative = false 250 | 251 | normalize(a) 252 | assert tmp == 0 253 | 254 | template realUnsignedSubtraction(a: var BigInt, b, c: BigInt) = 255 | # b > c 256 | let 257 | bl = b.limbs.len 258 | cl = c.limbs.len 259 | var m = min(bl, cl) 260 | a.limbs.setLen(max(bl, cl)) 261 | 262 | var tmp = 0'i64 263 | for i in 0 ..< m: 264 | tmp = int64(uint32.high) + 1 + int64(b.limbs[i]) - int64(c.limbs[i]) - tmp 265 | a.limbs[i] = uint32(tmp and int64(uint32.high)) 266 | tmp = 1 - (tmp shr 32) 267 | if bl < cl: 268 | for i in m ..< cl: 269 | tmp = int64(uint32.high) + 1 - int64(c.limbs[i]) - tmp 270 | a.limbs[i] = uint32(tmp and int64(uint32.high)) 271 | tmp = 1 - (tmp shr 32) 272 | a.isNegative = true 273 | else: 274 | for i in m ..< bl: 275 | tmp = int64(uint32.high) + 1 + int64(b.limbs[i]) - tmp 276 | a.limbs[i] = uint32(tmp and int64(uint32.high)) 277 | tmp = 1 - (tmp shr 32) 278 | a.isNegative = false 279 | 280 | normalize(a) 281 | assert tmp == 0 282 | 283 | func unsignedSubtractionInt(a: var BigInt, b: BigInt, c: uint32) = 284 | # `b` is not zero 285 | let cmpRes = unsignedCmp(b, c) 286 | if cmpRes > 0: 287 | realUnsignedSubtractionInt(a, b, c) 288 | elif cmpRes < 0: 289 | # `b` is only a single limb 290 | a.limbs = @[c - b.limbs[0]] 291 | a.isNegative = true 292 | else: # b == c 293 | a = zero 294 | 295 | func unsignedSubtraction(a: var BigInt, b, c: BigInt) = 296 | let cmpRes = unsignedCmp(b, c) 297 | if cmpRes > 0: 298 | realUnsignedSubtraction(a, b, c) 299 | elif cmpRes < 0: 300 | realUnsignedSubtraction(a, c, b) 301 | a.negate() 302 | else: # b == c 303 | a = zero 304 | 305 | func additionInt(a: var BigInt, b: BigInt, c: int32) = 306 | # a = b + c 307 | if b.isZero: 308 | a = c.initBigInt 309 | elif b.isNegative: 310 | if c < 0: 311 | unsignedAdditionInt(a, b, (not c).uint32 + 1) 312 | else: 313 | unsignedSubtractionInt(a, b, c.uint32) 314 | a.negate() 315 | else: 316 | if c < 0: 317 | unsignedSubtractionInt(a, b, (not c).uint32 + 1) 318 | else: 319 | unsignedAdditionInt(a, b, c.uint32) 320 | 321 | func addition(a: var BigInt, b, c: BigInt) = 322 | # a = b + c 323 | if b.isNegative: 324 | if c.isNegative: 325 | unsignedAddition(a, b, c) 326 | a.isNegative = true 327 | else: 328 | unsignedSubtraction(a, c, b) 329 | else: 330 | if c.isNegative: 331 | unsignedSubtraction(a, b, c) 332 | else: 333 | unsignedAddition(a, b, c) 334 | 335 | func `+`*(a, b: BigInt): BigInt = 336 | ## Addition for `BigInt`s. 337 | runnableExamples: 338 | let 339 | a = 5.initBigInt 340 | b = 10.initBigInt 341 | assert a + b == 15.initBigInt 342 | assert (-a) + b == 5.initBigInt 343 | assert a + (-b) == -5.initBigInt 344 | addition(result, a, b) 345 | 346 | template `+=`*(a: var BigInt, b: BigInt) = 347 | runnableExamples: 348 | var a = 5.initBigInt 349 | a += 2.initBigInt 350 | assert a == 7.initBigInt 351 | a = a + b 352 | 353 | func subtractionInt(a: var BigInt, b: BigInt, c: int32) = 354 | # a = b - c 355 | if b.isZero: 356 | a = -c.initBigInt 357 | elif b.isNegative: 358 | if c < 0: 359 | unsignedSubtractionInt(a, b, (not c).uint32 + 1) 360 | else: 361 | unsignedAdditionInt(a, b, c.uint32) 362 | a.negate() 363 | else: 364 | if c < 0: 365 | unsignedAdditionInt(a, b, (not c).uint32 + 1) 366 | else: 367 | unsignedSubtractionInt(a, b, c.uint32) 368 | 369 | func subtraction(a: var BigInt, b, c: BigInt) = 370 | # a = b - c 371 | if b.isNegative: 372 | if c.isNegative: 373 | unsignedSubtraction(a, c, b) 374 | else: 375 | unsignedAddition(a, b, c) 376 | a.isNegative = true 377 | else: 378 | if c.isNegative: 379 | unsignedAddition(a, b, c) 380 | else: 381 | unsignedSubtraction(a, b, c) 382 | 383 | func `-`*(a, b: BigInt): BigInt = 384 | ## Subtraction for `BigInt`s. 385 | runnableExamples: 386 | let 387 | a = 15.initBigInt 388 | b = 10.initBigInt 389 | assert a - b == 5.initBigInt 390 | assert (-a) - b == -25.initBigInt 391 | assert a - (-b) == 25.initBigInt 392 | subtraction(result, a, b) 393 | 394 | template `-=`*(a: var BigInt, b: BigInt) = 395 | runnableExamples: 396 | var a = 5.initBigInt 397 | a -= 2.initBigInt 398 | assert a == 3.initBigInt 399 | a = a - b 400 | 401 | 402 | func unsignedMultiplication(a: var BigInt, b, c: BigInt) {.inline.} = 403 | # always called with bl >= cl 404 | let 405 | bl = b.limbs.len 406 | cl = c.limbs.len 407 | a.limbs.setLen(bl + cl) 408 | var tmp = 0'u64 409 | 410 | for i in 0 ..< bl: 411 | tmp += uint64(b.limbs[i]) * uint64(c.limbs[0]) 412 | a.limbs[i] = uint32(tmp and uint32.high) 413 | tmp = tmp shr 32 414 | 415 | a.limbs[bl] = uint32(tmp) 416 | 417 | for j in 1 ..< cl: 418 | tmp = 0'u64 419 | for i in 0 ..< bl: 420 | tmp += uint64(a.limbs[j + i]) + uint64(b.limbs[i]) * uint64(c.limbs[j]) 421 | a.limbs[j + i] = uint32(tmp and uint32.high) 422 | tmp = tmp shr 32 423 | var pos = j + bl 424 | while tmp > 0'u64: 425 | tmp += uint64(a.limbs[pos]) 426 | a.limbs[pos] = uint32(tmp and uint32.high) 427 | tmp = tmp shr 32 428 | inc pos 429 | normalize(a) 430 | 431 | func multiplication(a: var BigInt, b, c: BigInt) = 432 | # a = b * c 433 | if b.isZero or c.isZero: 434 | a = zero 435 | return 436 | let 437 | bl = b.limbs.len 438 | cl = c.limbs.len 439 | 440 | if cl > bl: 441 | unsignedMultiplication(a, c, b) 442 | else: 443 | unsignedMultiplication(a, b, c) 444 | a.isNegative = b.isNegative xor c.isNegative 445 | 446 | func `*`*(a, b: BigInt): BigInt = 447 | ## Multiplication for `BigInt`s. 448 | runnableExamples: 449 | let 450 | a = 421.initBigInt 451 | b = 200.initBigInt 452 | assert a * b == 84200.initBigInt 453 | multiplication(result, a, b) 454 | 455 | template `*=`*(a: var BigInt, b: BigInt) = 456 | runnableExamples: 457 | var a = 15.initBigInt 458 | a *= 10.initBigInt 459 | assert a == 150.initBigInt 460 | a = a * b 461 | 462 | func pow*(x: BigInt, y: Natural): BigInt = 463 | ## Computes `x` to the power of `y`. 464 | var base = x 465 | var exp = y 466 | result = one 467 | 468 | # binary exponentiation 469 | while exp > 0: 470 | if (exp and 1) > 0: 471 | result *= base 472 | exp = exp shr 1 473 | base *= base 474 | 475 | func `shl`*(x: BigInt, y: Natural): BigInt = 476 | ## Shifts a `BigInt` to the left. 477 | runnableExamples: 478 | let a = 24.initBigInt 479 | assert a shl 1 == 48.initBigInt 480 | assert a shl 2 == 96.initBigInt 481 | 482 | if x.isZero: 483 | return x 484 | 485 | var carry = 0'u64 486 | let a = y div 32 487 | let b = uint32(y mod 32) 488 | let mask = ((1'u64 shl b) - 1) shl (64 - b) 489 | result.limbs.setLen(x.limbs.len + a) 490 | result.isNegative = x.isNegative 491 | 492 | for i in countup(0, x.limbs.high): 493 | let acc = (uint64(x.limbs[i]) shl 32) or carry 494 | carry = (acc and mask) shr 32 495 | result.limbs[i + a] = uint32((acc shl b) shr 32) 496 | 497 | if carry > 0: 498 | result.limbs.add(uint32(carry shr (32 - b))) 499 | 500 | func `shr`*(x: BigInt, y: Natural): BigInt = 501 | ## Shifts a `BigInt` to the right (arithmetically). 502 | runnableExamples: 503 | let a = 24.initBigInt 504 | assert a shr 1 == 12.initBigInt 505 | assert a shr 2 == 6.initBigInt 506 | 507 | var carry = 0'u64 508 | let a = y div 32 509 | if a >= x.limbs.len: 510 | return zero 511 | let b = uint32(y mod 32) 512 | let mask = (1'u32 shl b) - 1 513 | result.limbs.setLen(x.limbs.len - a) 514 | result.isNegative = x.isNegative 515 | 516 | for i in countdown(x.limbs.high, a): 517 | let acc = (carry shl 32) or x.limbs[i] 518 | carry = acc and mask 519 | result.limbs[i - a] = uint32(acc shr b) 520 | 521 | if result.isNegative: 522 | var underflow = false 523 | if carry > 0: 524 | underflow = true 525 | else: 526 | for i in 0 .. a - 1: 527 | if x.limbs[i] > 0: 528 | underflow = true 529 | break 530 | 531 | if underflow: 532 | dec result 533 | 534 | if result.limbs.len > 1 and result.limbs[result.limbs.high] == 0: 535 | # normalize 536 | result.limbs.setLen(result.limbs.high) 537 | 538 | 539 | # bitwise operations 540 | 541 | func invertIn(a: BigInt): BigInt {.inline.} = 542 | result = a 543 | result.isNegative = false 544 | dec(result) 545 | 546 | func invertOut(a: var BigInt) {.inline.} = 547 | inc(a) 548 | a.isNegative = true 549 | 550 | func `not`*(a: BigInt): BigInt = 551 | ## Bitwise `not` for `BigInt`s. 552 | # 2's complement: -x = not x + 1 <=> not x = -x - 1 = -(x + 1) 553 | result = succ(a) 554 | negate(result) 555 | 556 | func `and`*(a, b: BigInt): BigInt = 557 | ## Bitwise `and` for `BigInt`s. 558 | if a.isNegative and not a.isZero: 559 | if b.isNegative and not b.isZero: 560 | # - and - 561 | let a = invertIn(a) 562 | let b = invertIn(b) 563 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 564 | let m = min(a.limbs.len, b.limbs.len) 565 | for i in 0 ..< m: 566 | result.limbs[i] = a.limbs[i] or b.limbs[i] 567 | for i in m ..< a.limbs.len: 568 | result.limbs[i] = a.limbs[i] 569 | for i in m ..< b.limbs.len: 570 | result.limbs[i] = b.limbs[i] 571 | invertOut(result) 572 | else: 573 | # - and + 574 | let a = invertIn(a) 575 | result = b 576 | for i in 0 ..< min(a.limbs.len, b.limbs.len): 577 | result.limbs[i] = (not a.limbs[i]) and b.limbs[i] 578 | else: 579 | if b.isNegative and not b.isZero: 580 | # + and - 581 | let b = invertIn(b) 582 | result = a 583 | for i in 0 ..< min(a.limbs.len, b.limbs.len): 584 | result.limbs[i] = a.limbs[i] and (not b.limbs[i]) 585 | else: 586 | # + and + 587 | result.limbs.setLen(min(a.limbs.len, b.limbs.len)) 588 | for i in 0 ..< result.limbs.len: 589 | result.limbs[i] = a.limbs[i] and b.limbs[i] 590 | normalize(result) 591 | 592 | func `or`*(a, b: BigInt): BigInt = 593 | ## Bitwise `or` for `BigInt`s. 594 | if a.isNegative and not a.isZero: 595 | if b.isNegative and not b.isZero: 596 | # - or - 597 | let a = invertIn(a) 598 | let b = invertIn(b) 599 | result.limbs.setLen(min(a.limbs.len, b.limbs.len)) 600 | for i in 0 ..< result.limbs.len: 601 | result.limbs[i] = a.limbs[i] and b.limbs[i] 602 | invertOut(result) 603 | else: 604 | # - or + 605 | let a = invertIn(a) 606 | result = a 607 | for i in 0 ..< min(a.limbs.len, b.limbs.len): 608 | result.limbs[i] = a.limbs[i] and (not b.limbs[i]) 609 | invertOut(result) 610 | else: 611 | if b.isNegative and not b.isZero: 612 | # + or - 613 | let b = invertIn(b) 614 | result = b 615 | for i in 0 ..< min(a.limbs.len, b.limbs.len): 616 | result.limbs[i] = (not a.limbs[i]) and b.limbs[i] 617 | invertOut(result) 618 | else: 619 | # + or + 620 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 621 | let m = min(a.limbs.len, b.limbs.len) 622 | for i in 0 ..< m: 623 | result.limbs[i] = a.limbs[i] or b.limbs[i] 624 | for i in m ..< a.limbs.len: 625 | result.limbs[i] = a.limbs[i] 626 | for i in m ..< b.limbs.len: 627 | result.limbs[i] = b.limbs[i] 628 | normalize(result) 629 | 630 | func `xor`*(a, b: BigInt): BigInt = 631 | ## Bitwise `xor` for `BigInt`s. 632 | if a.isNegative and not a.isZero: 633 | if b.isNegative and not b.isZero: 634 | # - xor - 635 | let a = invertIn(a) 636 | let b = invertIn(b) 637 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 638 | let m = min(a.limbs.len, b.limbs.len) 639 | for i in 0 ..< m: 640 | result.limbs[i] = a.limbs[i] xor b.limbs[i] 641 | for i in m ..< a.limbs.len: 642 | result.limbs[i] = a.limbs[i] 643 | for i in m ..< b.limbs.len: 644 | result.limbs[i] = b.limbs[i] 645 | else: 646 | # - xor + 647 | let a = invertIn(a) 648 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 649 | let m = min(a.limbs.len, b.limbs.len) 650 | for i in 0 ..< m: 651 | result.limbs[i] = a.limbs[i] xor b.limbs[i] 652 | for i in m ..< a.limbs.len: 653 | result.limbs[i] = a.limbs[i] 654 | for i in m ..< b.limbs.len: 655 | result.limbs[i] = b.limbs[i] 656 | invertOut(result) 657 | else: 658 | if b.isNegative and not b.isZero: 659 | # + xor - 660 | let b = invertIn(b) 661 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 662 | let m = min(a.limbs.len, b.limbs.len) 663 | for i in 0 ..< m: 664 | result.limbs[i] = a.limbs[i] xor b.limbs[i] 665 | for i in m ..< a.limbs.len: 666 | result.limbs[i] = a.limbs[i] 667 | for i in m ..< b.limbs.len: 668 | result.limbs[i] = b.limbs[i] 669 | invertOut(result) 670 | else: 671 | # + xor + 672 | result.limbs.setLen(max(a.limbs.len, b.limbs.len)) 673 | let m = min(a.limbs.len, b.limbs.len) 674 | for i in 0 ..< m: 675 | result.limbs[i] = a.limbs[i] xor b.limbs[i] 676 | for i in m ..< a.limbs.len: 677 | result.limbs[i] = a.limbs[i] 678 | for i in m ..< b.limbs.len: 679 | result.limbs[i] = b.limbs[i] 680 | normalize(result) 681 | 682 | 683 | func reset(a: var BigInt) = 684 | ## Resets a `BigInt` back to the zero value. 685 | a.limbs.setLen(1) 686 | a.limbs[0] = 0 687 | a.isNegative = false 688 | 689 | func unsignedDivRem(q: var BigInt, r: var uint32, n: BigInt, d: uint32) = 690 | q.limbs.setLen(n.limbs.len) 691 | r = 0 692 | for i in countdown(n.limbs.high, 0): 693 | let tmp = uint64(n.limbs[i]) + uint64(r) shl 32 694 | q.limbs[i] = uint32(tmp div d) 695 | r = uint32(tmp mod d) 696 | normalize(q) 697 | 698 | func bits(d: uint32): int = 699 | const bitLengths = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 700 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5] 701 | var d = d 702 | while d >= 32'u32: 703 | result += 6 704 | d = d shr 6 705 | result += bitLengths[int(d)] 706 | 707 | # From Knuth and Python 708 | func unsignedDivRem(q, r: var BigInt, n, d: BigInt) = 709 | var 710 | nn = n.limbs.len 711 | dn = d.limbs.len 712 | 713 | if n.isZero: 714 | q = zero 715 | r = zero 716 | elif nn < dn: 717 | # n < d 718 | q = zero 719 | r = n 720 | elif dn == 1: 721 | var x: uint32 722 | unsignedDivRem(q, x, n, d.limbs[0]) 723 | r.limbs = @[x] 724 | r.isNegative = false 725 | else: 726 | assert nn >= dn and dn >= 2 727 | 728 | # normalize 729 | let ls = 32 - bits(d.limbs[d.limbs.high]) 730 | r = d shl ls 731 | q = n shl ls 732 | if q.limbs.len > n.limbs.len or q.limbs[q.limbs.high] >= r.limbs[r.limbs.high]: 733 | q.limbs.add(0'u32) 734 | inc(nn) 735 | 736 | let k = nn - dn 737 | assert k >= 0 738 | var a: BigInt 739 | a.limbs.setLen(k) 740 | let wm1 = r.limbs[r.limbs.high] 741 | let wm2 = r.limbs[r.limbs.high-1] 742 | var ak = k 743 | 744 | var zhi = zero 745 | var z = zero 746 | var qib = zero 747 | var q1b = zero 748 | 749 | for v in countdown(k-1, 0): 750 | # estimate quotient digit, may rarely overestimate by 1 751 | let vtop = q.limbs[v + dn] 752 | assert vtop <= wm1 753 | let vv = (uint64(vtop) shl 32) or q.limbs[v+dn-1] 754 | var q1 = vv div wm1 755 | var r1 = vv mod wm1 756 | 757 | while (wm2 * q1) > ((r1 shl 32) or q.limbs[v+dn-2]): 758 | dec q1 759 | r1 += wm1 760 | if r1 > uint32.high: 761 | break 762 | 763 | assert q1 <= uint32.high 764 | 765 | q1b.limbs[0] = uint32(q1) 766 | 767 | # subtract 768 | zhi.reset() 769 | for i in 0 ..< dn: 770 | z.reset() 771 | z.limbs[0] = r.limbs[i] 772 | z *= q1b 773 | z.isNegative = true 774 | z += zhi 775 | var z1 = z 776 | qib.limbs[0] = q.limbs[v+i] 777 | z += qib 778 | 779 | if z < 0: 780 | q.limbs[v+i] = not z.limbs[0] + 1 781 | else: 782 | q.limbs[v+i] = z.limbs[0] 783 | 784 | if z.limbs.len > 1: 785 | zhi.limbs[0] = z1.limbs[1] 786 | if z1.limbs[0] > qib.limbs[0]: 787 | zhi.limbs[0] += 1 788 | zhi.isNegative = true 789 | elif z < 0: 790 | zhi.limbs[0] = 1 791 | zhi.isNegative = true 792 | else: 793 | zhi.reset() 794 | 795 | # add back if was too large (rare branch) 796 | if vtop.initBigInt + zhi < 0: 797 | var carry = 0'u64 798 | for i in 0 ..< dn: 799 | carry += q.limbs[v+i] 800 | carry += r.limbs[i] 801 | q.limbs[v+i] = uint32(carry and uint32.high) 802 | carry = carry shr 32 803 | dec(q1) 804 | 805 | # store quotient digit 806 | assert q1 <= uint32.high 807 | dec(ak) 808 | a.limbs[ak] = uint32(q1) 809 | 810 | # unshift remainder, we reuse w1 to store the result 811 | q.limbs.setLen(dn) 812 | r = q shr ls 813 | 814 | normalize(r) 815 | q = a 816 | normalize(q) 817 | 818 | func division(q, r: var BigInt, n, d: BigInt) = 819 | # q = n div d 820 | # r = n mod d 821 | if d.isZero: 822 | raise newException(DivByZeroDefect, "division by zero") 823 | 824 | unsignedDivRem(q, r, n, d) 825 | 826 | q.isNegative = n < 0 xor d < 0 827 | r.isNegative = n < 0 and r != 0 828 | 829 | # divrem -> divmod 830 | if (r < 0 and d > 0) or (r > 0 and d < 0): 831 | r += d 832 | q -= one 833 | 834 | func `div`*(a, b: BigInt): BigInt = 835 | ## Computes the integer division of two `BigInt` numbers. 836 | ## Raises a `DivByZeroDefect` if `b` is zero. 837 | ## 838 | ## If you also need the modulo (remainder), use the `divmod func <#divmod,BigInt,BigInt>`_. 839 | runnableExamples: 840 | let 841 | a = 17.initBigInt 842 | b = 5.initBigInt 843 | assert a div b == 3.initBigInt 844 | assert (-a) div b == -4.initBigInt 845 | assert a div (-b) == -4.initBigInt 846 | assert (-a) div (-b) == 3.initBigInt 847 | var tmp: BigInt 848 | division(result, tmp, a, b) 849 | 850 | func `mod`*(a, b: BigInt): BigInt = 851 | ## Computes the integer modulo (remainder) of two `BigInt` numbers. 852 | ## Raises a `DivByZeroDefect` if `b` is zero. 853 | ## 854 | ## If you also need an integer division, use the `divmod func <#divmod,BigInt,BigInt>`_. 855 | runnableExamples: 856 | let 857 | a = 17.initBigInt 858 | b = 5.initBigInt 859 | assert a mod b == 2.initBigInt 860 | assert (-a) mod b == 3.initBigInt 861 | assert a mod (-b) == -3.initBigInt 862 | assert (-a) mod (-b) == -2.initBigInt 863 | var tmp: BigInt 864 | division(tmp, result, a, b) 865 | 866 | func divmod*(a, b: BigInt): tuple[q, r: BigInt] = 867 | ## Computes both the integer division and modulo (remainder) of two 868 | ## `BigInt` numbers. 869 | ## Raises a `DivByZeroDefect` if `b` is zero. 870 | runnableExamples: 871 | let 872 | a = 17.initBigInt 873 | b = 5.initBigInt 874 | assert divmod(a, b) == (3.initBigInt, 2.initBigInt) 875 | division(result.q, result.r, a, b) 876 | 877 | func countTrailingZeroBits(a: BigInt): int = 878 | var count = 0 879 | for x in a.limbs: 880 | if x == 0: 881 | count += 32 882 | else: 883 | return count + countTrailingZeroBits(x) 884 | return count 885 | 886 | func gcd*(a, b: BigInt): BigInt = 887 | ## Returns the greatest common divisor (GCD) of `a` and `b`. 888 | runnableExamples: 889 | assert gcd(54.initBigInt, 24.initBigInt) == 6.initBigInt 890 | 891 | # binary GCD algorithm 892 | var 893 | u = abs(a) 894 | v = abs(b) 895 | if u.isZero: 896 | return v 897 | elif v.isZero: 898 | return u 899 | let 900 | i = countTrailingZeroBits(u) 901 | j = countTrailingZeroBits(v) 902 | k = min(i, j) 903 | u = u shr i 904 | v = v shr j 905 | while true: 906 | # u and v are odd 907 | if u > v: 908 | swap(u, v) 909 | v -= u 910 | if v.isZero: 911 | return u shl k 912 | v = v shr countTrailingZeroBits(v) 913 | 914 | 915 | func toInt*[T: SomeInteger](x: BigInt): Option[T] = 916 | ## Converts a `BigInt` number to an integer, if possible. 917 | ## If the `BigInt` doesn't fit in a `T`, returns `none(T)`; 918 | ## otherwise returns `some(x)`. 919 | runnableExamples: 920 | import std/options 921 | let 922 | a = 44.initBigInt 923 | b = 130.initBigInt 924 | assert toInt[int8](a) == some(44'i8) 925 | assert toInt[int8](b) == none(int8) 926 | assert toInt[uint8](b) == some(130'u8) 927 | assert toInt[int](b) == some(130) 928 | 929 | if x.isZero: 930 | return some(default(T)) # default(T) is 0 931 | when T is SomeSignedInt: 932 | # T is signed 933 | when sizeof(T) == 8: 934 | if x.limbs.len > 2: 935 | result = none(T) 936 | elif x.limbs.len == 2: 937 | if x.isNegative: 938 | if x.limbs[1] > uint32(int32.high) + 1 or (x.limbs[1] == uint32(int32.high) + 1 and x.limbs[0] > 0): 939 | result = none(T) 940 | else: 941 | let value = not T(x.limbs[1].uint64 shl 32 + x.limbs[0] - 1) 942 | result = some(value) 943 | else: 944 | if x.limbs[1] > uint32(int32.high): 945 | result = none(T) 946 | else: 947 | let value = T(x.limbs[1].uint64 shl 32 + x.limbs[0]) 948 | result = some(value) 949 | else: 950 | if x.isNegative: 951 | result = some(not T(x.limbs[0] - 1)) 952 | else: 953 | result = some(T(x.limbs[0])) 954 | else: 955 | if x.limbs.len > 1: 956 | result = none(T) 957 | else: 958 | if x.isNegative: 959 | if x.limbs[0] > uint32(T.high) + 1: 960 | result = none(T) 961 | else: 962 | result = some(not T(x.limbs[0] - 1)) 963 | else: 964 | if x.limbs[0] > uint32(T.high): 965 | result = none(T) 966 | else: 967 | result = some(T(x.limbs[0])) 968 | else: 969 | # T is unsigned 970 | if x.isNegative: 971 | return none(T) 972 | when sizeof(T) == 8: 973 | if x.limbs.len > 2: 974 | result = none(T) 975 | elif x.limbs.len == 2: 976 | let value = T(x.limbs[1]) shl 32 + T(x.limbs[0]) 977 | result = some(value) 978 | else: 979 | result = some(T(x.limbs[0])) 980 | else: 981 | if x.limbs.len > 1: 982 | result = none(T) 983 | elif x.limbs[0] > uint32(T.high): 984 | result = none(T) 985 | else: 986 | result = some(T(x.limbs[0])) 987 | 988 | func calcSizes(): array[2..36, int] = 989 | for i in 2..36: 990 | var x = int64(i) 991 | while x <= int64(uint32.high) + 1: 992 | x *= i 993 | result[i].inc 994 | 995 | const 996 | digits = "0123456789abcdefghijklmnopqrstuvwxyz" 997 | powers = {2'u8, 4, 8, 16, 32} 998 | sizes = calcSizes() # `sizes[base]` is the maximum number of digits that fully fit in a `uint32` 999 | 1000 | func toString*(a: BigInt, base: range[2..36] = 10): string = 1001 | ## Produces a string representation of a `BigInt` in a specified 1002 | ## `base`. 1003 | ## 1004 | ## Doesn't produce any prefixes (`0x`, `0b`, etc.). 1005 | runnableExamples: 1006 | let a = 55.initBigInt 1007 | assert toString(a) == "55" 1008 | assert toString(a, 2) == "110111" 1009 | assert toString(a, 16) == "37" 1010 | 1011 | if a.isZero: 1012 | return "0" 1013 | 1014 | let size = sizes[base] 1015 | if base.uint8 in powers: 1016 | let 1017 | bits = countTrailingZeroBits(base) # bits per digit 1018 | mask = (1'u32 shl bits) - 1 1019 | totalBits = 32 * a.limbs.len - countLeadingZeroBits(a.limbs[a.limbs.high]) 1020 | result = newStringOfCap((totalBits + bits - 1) div bits + 1) 1021 | 1022 | var 1023 | acc = 0'u32 1024 | accBits = 0 # the number of bits needed for acc 1025 | for x in a.limbs: 1026 | acc = acc or (x shl accBits) 1027 | accBits += 32 1028 | while accBits >= bits: 1029 | result.add(digits[acc and mask]) 1030 | acc = acc shr bits 1031 | if accBits > 32: 1032 | acc = x shr (32 - (accBits - bits)) 1033 | accBits -= bits 1034 | if acc > 0: 1035 | result.add(digits[acc]) 1036 | else: 1037 | let 1038 | base = uint32(base) 1039 | d = base ^ size 1040 | var tmp = a 1041 | 1042 | tmp.isNegative = false 1043 | result = newStringOfCap(size * a.limbs.len + 1) # estimate the length of the result 1044 | 1045 | while tmp > 0: 1046 | var 1047 | c: uint32 1048 | tmpCopy = tmp 1049 | unsignedDivRem(tmp, c, tmpCopy, d) 1050 | for i in 1..size: 1051 | result.add(digits[c mod base]) 1052 | c = c div base 1053 | 1054 | # normalize 1055 | var i = result.high 1056 | while i > 0 and result[i] == '0': 1057 | dec i 1058 | result.setLen(i+1) 1059 | 1060 | if a.isNegative: 1061 | result.add('-') 1062 | 1063 | result.reverse() 1064 | 1065 | func `$`*(a: BigInt): string = 1066 | ## String representation of a `BigInt` in base 10. 1067 | toString(a, 10) 1068 | 1069 | func parseDigit(c: char, base: uint32): uint32 {.inline.} = 1070 | result = case c 1071 | of '0'..'9': uint32(ord(c) - ord('0')) 1072 | of 'a'..'z': uint32(ord(c) - ord('a') + 10) 1073 | of 'A'..'Z': uint32(ord(c) - ord('A') + 10) 1074 | else: raise newException(ValueError, "Invalid input: " & c) 1075 | 1076 | if result >= base: 1077 | raise newException(ValueError, "Invalid input: " & c) 1078 | 1079 | func filterUnderscores(str: var string) {.inline.} = 1080 | var k = 0 # the amount of underscores 1081 | for i in 0 .. str.high: 1082 | let c = str[i] 1083 | if c == '_': 1084 | inc k 1085 | elif k > 0: 1086 | str[i - k] = c 1087 | str.setLen(str.len - k) 1088 | 1089 | func initBigInt*(str: string, base: range[2..36] = 10): BigInt = 1090 | ## Create a `BigInt` from a string. For invalid inputs, a `ValueError` exception is raised. 1091 | runnableExamples: 1092 | let 1093 | a = initBigInt("1234") 1094 | b = initBigInt("1234", base = 8) 1095 | assert a == 1234.initBigInt 1096 | assert b == 668.initBigInt 1097 | 1098 | if str.len == 0: 1099 | raise newException(ValueError, "Empty input") 1100 | 1101 | let size = sizes[base] 1102 | let base = base.uint32 1103 | var first = 0 1104 | var neg = false 1105 | 1106 | case str[0] 1107 | of '-': 1108 | if str.len == 1: 1109 | raise newException(ValueError, "Invalid input: " & str) 1110 | first = 1 1111 | neg = true 1112 | of '+': 1113 | if str.len == 1: 1114 | raise newException(ValueError, "Invalid input: " & str) 1115 | first = 1 1116 | else: 1117 | discard 1118 | if str[first] == '_': 1119 | raise newException(ValueError, "A number can not begin with _") 1120 | if str[^1] == '_': 1121 | raise newException(ValueError, "A number can not end with _") 1122 | 1123 | if base.uint8 in powers: 1124 | # base is a power of two, so each digit corresponds to a block of bits 1125 | let bits = countTrailingZeroBits(base) # bits per digit 1126 | var 1127 | acc = 0'u32 1128 | accBits = 0 # the number of bits needed for acc 1129 | for i in countdown(str.high, first): 1130 | if str[i] != '_': 1131 | let digit = parseDigit(str[i], base) 1132 | acc = acc or (digit shl accBits) 1133 | accBits += bits 1134 | if accBits >= 32: 1135 | result.limbs.add(acc) 1136 | accBits -= 32 1137 | acc = digit shr (bits - accBits) 1138 | if acc > 0: 1139 | result.limbs.add(acc) 1140 | result.normalize() 1141 | else: 1142 | var str = str 1143 | filterUnderscores(str) 1144 | let d = initBigInt(base ^ size) 1145 | for i in countup(first, str.high, size): 1146 | var num = 0'u32 # the accumulator in this block 1147 | if i + size <= str.len: 1148 | # iterator over a block of length `size`, so we can use `d` 1149 | for j in countup(i, i + size - 1): 1150 | if str[j] != '_': 1151 | let digit = parseDigit(str[j], base) 1152 | num = (num * base) + digit 1153 | unsignedAdditionInt(result, result * d, num) 1154 | else: 1155 | # iterator over a block smaller than `size`, so we have to compute `mul` 1156 | var mul = 1'u32 # the multiplication factor for num 1157 | for j in countup(i, min(i + size - 1, str.high)): 1158 | if str[j] != '_': 1159 | let digit = parseDigit(str[j], base) 1160 | num = (num * base) + digit 1161 | mul *= base 1162 | unsignedAdditionInt(result, result * initBigInt(mul), num) 1163 | 1164 | result.isNegative = neg 1165 | 1166 | when (NimMajor, NimMinor) >= (1, 5): 1167 | include bigints/private/literals 1168 | 1169 | func inc*(a: var BigInt, b: int = 1) = 1170 | ## Increase the value of a `BigInt` by the specified amount (default: 1). 1171 | runnableExamples: 1172 | var a = 15.initBigInt 1173 | inc a 1174 | assert a == 16.initBigInt 1175 | inc(a, 7) 1176 | assert a == 23.initBigInt 1177 | 1178 | if b in int32.low..int32.high: 1179 | var c = a 1180 | additionInt(a, c, b.int32) 1181 | else: 1182 | a += initBigInt(b) 1183 | 1184 | func dec*(a: var BigInt, b: int = 1) = 1185 | ## Decrease the value of a `BigInt` by the specified amount (default: 1). 1186 | runnableExamples: 1187 | var a = 15.initBigInt 1188 | dec a 1189 | assert a == 14.initBigInt 1190 | dec(a, 5) 1191 | assert a == 9.initBigInt 1192 | 1193 | if b in int32.low..int32.high: 1194 | var c = a 1195 | subtractionInt(a, c, b.int32) 1196 | else: 1197 | a -= initBigInt(b) 1198 | 1199 | func succ*(a: BigInt, b: int = 1): BigInt = 1200 | ## Returns the `b`-th successor of a `BigInt`. 1201 | result = a 1202 | inc(result, b) 1203 | 1204 | func pred*(a: BigInt, b: int = 1): BigInt = 1205 | ## Returns the `b`-th predecessor of a `BigInt`. 1206 | result = a 1207 | dec(result, b) 1208 | 1209 | 1210 | iterator countup*(a, b: BigInt, step: int32 = 1): BigInt = 1211 | ## Counts from `a` up to `b` (inclusive) with the given step count. 1212 | var res = a 1213 | while res <= b: 1214 | yield res 1215 | inc(res, step) 1216 | 1217 | iterator countdown*(a, b: BigInt, step: int32 = 1): BigInt = 1218 | ## Counts from `a` down to `b` (inclusive) with the given step count. 1219 | var res = a 1220 | while res >= b: 1221 | yield res 1222 | dec(res, step) 1223 | 1224 | iterator `..`*(a, b: BigInt): BigInt = 1225 | ## Counts from `a` up to `b` (inclusive). 1226 | var res = a 1227 | while res <= b: 1228 | yield res 1229 | inc res 1230 | 1231 | iterator `..<`*(a, b: BigInt): BigInt = 1232 | ## Counts from `a` up to `b` (exclusive). 1233 | var res = a 1234 | while res < b: 1235 | yield res 1236 | inc res 1237 | 1238 | 1239 | func modulo(a, modulus: BigInt): BigInt = 1240 | ## Like `mod`, but the result is always in the range `[0, modulus-1]`. 1241 | ## `modulus` should be greater than zero. 1242 | result = a mod modulus 1243 | if result < 0: 1244 | result += modulus 1245 | 1246 | func fastLog2*(a: BigInt): int = 1247 | ## Computes the logarithm in base 2 of `a`. 1248 | ## If `a` is negative, returns the logarithm of `abs(a)`. 1249 | ## If `a` is zero, returns -1. 1250 | if a.isZero: 1251 | return -1 1252 | bitops.fastLog2(a.limbs[^1]) + 32*(a.limbs.high) 1253 | 1254 | 1255 | func invmod*(a, modulus: BigInt): BigInt = 1256 | ## Compute the modular inverse of `a` modulo `modulus`. 1257 | ## The return value is always in the range `[1, modulus-1]` 1258 | runnableExamples: 1259 | assert invmod(3.initBigInt, 7.initBigInt) == 5.initBigInt 1260 | 1261 | # extended Euclidean algorithm 1262 | if modulus.isZero: 1263 | raise newException(DivByZeroDefect, "modulus must be nonzero") 1264 | elif modulus.isNegative: 1265 | raise newException(ValueError, "modulus must be strictly positive") 1266 | elif a.isZero: 1267 | raise newException(DivByZeroDefect, "0 has no modular inverse") 1268 | else: 1269 | var 1270 | r0 = modulus 1271 | r1 = a.modulo(modulus) 1272 | t0 = zero 1273 | t1 = one 1274 | var rk, tk: BigInt # otherwise t1 is incorrectly inferred as cursor (https://github.com/nim-lang/Nim/issues/19457) 1275 | while r1 > 0: 1276 | let q = r0 div r1 1277 | rk = r0 - q * r1 1278 | tk = t0 - q * t1 1279 | r0 = r1 1280 | r1 = rk 1281 | t0 = t1 1282 | t1 = tk 1283 | if r0 != one: 1284 | raise newException(ValueError, $a & " has no modular inverse modulo " & $modulus) 1285 | result = t0.modulo(modulus) 1286 | 1287 | func powmod*(base, exponent, modulus: BigInt): BigInt = 1288 | ## Compute modular exponentation of `base` with power `exponent` modulo `modulus`. 1289 | ## The return value is always in the range `[0, modulus-1]`. 1290 | runnableExamples: 1291 | assert powmod(2.initBigInt, 3.initBigInt, 7.initBigInt) == 1.initBigInt 1292 | if modulus.isZero: 1293 | raise newException(DivByZeroDefect, "modulus must be nonzero") 1294 | elif modulus.isNegative: 1295 | raise newException(ValueError, "modulus must be strictly positive") 1296 | elif modulus == 1: 1297 | return zero 1298 | else: 1299 | var 1300 | base = base 1301 | exponent = exponent 1302 | if exponent < 0: 1303 | base = invmod(base, modulus) 1304 | exponent = -exponent 1305 | var basePow = base.modulo(modulus) 1306 | result = one 1307 | while not exponent.isZero: 1308 | if (exponent.limbs[0] and 1) != 0: 1309 | result = (result * basePow) mod modulus 1310 | basePow = (basePow * basePow) mod modulus 1311 | exponent = exponent shr 1 1312 | -------------------------------------------------------------------------------- /src/bigints/private/literals.nim: -------------------------------------------------------------------------------- 1 | # This is an include file, do not import it directly. 2 | # It is needed as a workaround for Nim's parser for versions <= 1.4. 3 | 4 | proc `'bi`*(s: string): BigInt = 5 | ## Create a `BigInt` from a literal, using the suffix `'bi`. 6 | runnableExamples: 7 | let 8 | a = 123'bi 9 | b = 0xFF'bi 10 | c = 0b1011'bi 11 | assert $a == "123" 12 | assert $b == "255" 13 | assert $c == "11" 14 | case s[0..min(s.high, 1)] 15 | of "0x", "0X": initBigInt(s[2..s.high], base = 16) 16 | of "0b", "0B": initBigInt(s[2..s.high], base = 2) 17 | else: initBigInt(s) 18 | -------------------------------------------------------------------------------- /src/bigints/random.nim: -------------------------------------------------------------------------------- 1 | import ../bigints 2 | import std/sequtils 3 | import std/options 4 | import std/random 5 | 6 | func rand*(r: var Rand, x: Slice[BigInt]): BigInt = 7 | ## Return a random `BigInt`, within the given range, using the given state. 8 | assert(x.a <= x.b, "invalid range") 9 | let 10 | spread = x.b - x.a 11 | # number of bits *not* including leading bit 12 | nbits = spread.fastLog2 13 | # number of limbs to generate completely randomly 14 | nFullLimbs = max(nbits div 32 - 1, 0) 15 | # highest possible value of the top two limbs. 16 | hi64Max = (spread shr (nFullLimbs*32)).toInt[:uint64].get() 17 | while true: 18 | # these limbs can be generated completely arbitrarily 19 | var limbs = newSeqWith(nFullLimbs, r.rand(uint32.low..uint32.high)) 20 | # generate the top two limbs more carefully. This all but guarantees 21 | # that the entire number is in the correct range 22 | let hi64 = r.rand(uint64.low..hi64Max) 23 | limbs.add(cast[uint32](hi64)) 24 | limbs.add(cast[uint32](hi64 shr 32)) 25 | result = initBigInt(limbs) 26 | if result <= spread: 27 | break 28 | result += x.a 29 | 30 | func rand*(r: var Rand, max: BigInt): BigInt = 31 | ## Return a random non-negative `BigInt`, up to `max`, using the given state. 32 | rand(r, 0.initBigInt..max) 33 | 34 | # backwards compatibility with 1.4 35 | when not defined(randState): 36 | var state = initRand(777) 37 | proc randState(): var Rand = state 38 | 39 | proc rand*(x: Slice[BigInt]): BigInt = rand(randState(), x) 40 | ## Return a random `BigInt`, within the given range. 41 | 42 | proc rand*(max: BigInt): BigInt = rand(randState(), max) 43 | ## Return a random `BigInt`, up to `max`. 44 | -------------------------------------------------------------------------------- /tests/nim.cfg: -------------------------------------------------------------------------------- 1 | path = "$projectPath/../src" 2 | -------------------------------------------------------------------------------- /tests/tbigints.nim: -------------------------------------------------------------------------------- 1 | import bigints 2 | import std/options 3 | 4 | const 5 | zero = initBigInt(0) 6 | one = initBigInt(1) 7 | 8 | proc main() = 9 | block: # initBigInt 10 | let a = 1234567.initBigInt 11 | doAssert $a == "1234567" 12 | 13 | let b = -1234567.initBigInt 14 | doAssert $b == "-1234567" 15 | 16 | let c = 123456789012345678.initBigInt 17 | doAssert $c == "123456789012345678" 18 | 19 | let d = -123456789012345678.initBigInt 20 | doAssert $d == "-123456789012345678" 21 | 22 | let e = int64.high.initBigInt 23 | doAssert $e == $int64.high 24 | 25 | let f = int64.low.initBigInt 26 | doAssert $f == $int64.low 27 | 28 | let g = (1'u64 shl 63).initBigInt 29 | doAssert $g == $(1'u64 shl 63) 30 | 31 | let h = 1234567.initBigInt 32 | let i = h.initBigInt 33 | doAssert $h == $i 34 | 35 | block: 36 | # + sign 37 | let plus = "+1234567".initBigInt 38 | doAssert $plus == "1234567" 39 | 40 | # Trailing underscores 41 | # after 1 digit 42 | let a = "1_234_567".initBigInt 43 | doAssert $a == "1234567" 44 | # after 2 digits 45 | let b = "12_345_678".initBigInt 46 | doAssert $b == "12345678" 47 | # after 3 digits 48 | let c = "123_456_789".initBigInt 49 | doAssert $c == "123456789" 50 | 51 | # Trailing underscores and + sign 52 | # after 1 digit 53 | let a2 = "+1_234_567".initBigInt 54 | doAssert $a2 == "1234567" 55 | # after 2 digits 56 | let b2 = "+12_345_678".initBigInt 57 | doAssert $b2 == "12345678" 58 | # after 3 digits 59 | let c2 = "+123_456_789".initBigInt 60 | doAssert $c2 == "123456789" 61 | let d2 = "+123_456_789_012_345_678".initBigInt 62 | doAssert $d2 == "123456789012345678" 63 | 64 | # Trailing underscores and - sign 65 | let a3 = "-1_234_567".initBigInt 66 | doAssert $a3 == "-1234567" 67 | # after 2 digits 68 | let b3 = "-12_345_678".initBigInt 69 | doAssert $b3 == "-12345678" 70 | # after 3 digits 71 | let c3 = "-123_456_789".initBigInt 72 | doAssert $c3 == "-123456789" 73 | let d3 = "-123_456_789_012_345_678".initBigInt 74 | doAssert $d3 == "-123456789012345678" 75 | 76 | block: 77 | # Wrong formatting of numbers should raise a ValueError 78 | doAssertRaises(ValueError): discard "+".initBigInt 79 | doAssertRaises(ValueError): discard "-".initBigInt 80 | doAssertRaises(ValueError): discard "+@1".initBigInt 81 | doAssertRaises(ValueError): discard "+_1".initBigInt 82 | doAssertRaises(ValueError): discard "_123_345_678".initBigInt 83 | doAssertRaises(ValueError): discard "_12_3_345_678".initBigInt 84 | 85 | # test various bit patterns at power-of-two boundaries 86 | block: 87 | proc chk[T](v: T) = 88 | doAssert $v == $(v.initBigInt) 89 | for bits in 0 .. 63: 90 | let x = 1'u64 shl bits 91 | let start = if x >= 8'u64: x - 8 else: 0'u64 92 | let stop = x + 8 93 | for vv in start .. stop: 94 | for v in [vv, not vv]: 95 | chk cast[int](v) 96 | chk v.uint 97 | chk cast[int64](v) 98 | chk v.uint64 99 | chk (v and int32.high.uint64).int32 100 | chk (v and uint32.high).uint32 101 | 102 | when (NimMajor, NimMinor) >= (1, 5): 103 | block: # literals 104 | # workaround 105 | include tliterals 106 | 107 | block: # zero 108 | # see https://github.com/nim-lang/bigints/issues/26 109 | # reported issue has an example about multiplication and it is due to a call to a.limbs[0] for an uninitialized a: BigInt 110 | # besides multiplication, one could look at appearances of [0] in source to find possible failures 111 | # failures bound to reaching a line with [0] are fatal 112 | # besides appearances of [0], also logic implemented through a.limbs.len might (and indeed does) show error 113 | # logic around sign might also play a role 114 | var 115 | zeroEmpty: BigInt # should be treated as zero, same with -zeroEmpty 116 | let 117 | bigOne: BigInt = initBigInt(@[0.uint32, 1]) 118 | 119 | # this came up in the above testing and can be though as secondary effect of unitialization (fix in negate?) 120 | doAssert $zero == "0" # ok 121 | doAssert $zeroEmpty == "0" # ok 122 | doAssert $(-zeroEmpty) == "0" # error: fixed 123 | 124 | # unsignedCmp(a, b: BigInt) has no [0] but it has logic with limbs.len 125 | doAssert zeroEmpty < one # ok 126 | doAssert zeroEmpty > -one # ok 127 | doAssert -zeroEmpty < one # ok 128 | doAssert -zeroEmpty > -one # ok 129 | doAssert not (zeroEmpty < zero) # error: fixed 130 | doAssert not (zeroEmpty > zero) # ok 131 | doAssert zeroEmpty == zero # error: fixed 132 | doAssert -zeroEmpty == zero # error: fixed 133 | 134 | # proc unsignedAddition(a: var BigInt, b, c: BigInt) 135 | doAssert zeroEmpty + one == one # ok 136 | doAssert one + zeroEmpty == one # ok 137 | doAssert -zeroEmpty + one == one # ok 138 | doAssert one + -zeroEmpty == one # ok 139 | doAssert zeroEmpty + zeroEmpty == zero # ok 140 | doAssert -zeroEmpty + zeroEmpty == zero # ok 141 | doAssert -zeroEmpty + -zeroEmpty == zero # ok 142 | doAssert zeroEmpty + -zeroEmpty == zero # ok 143 | doAssert bigOne + zeroEmpty == bigOne # ok 144 | doAssert bigOne + -zeroEmpty == bigOne # ok 145 | doAssert zeroEmpty + bigOne == bigOne # ok 146 | doAssert -zeroEmpty + bigOne == bigOne # ok 147 | doAssert -bigOne + zeroEmpty == -bigOne # ok 148 | doAssert -bigOne + -zeroEmpty == -bigOne # ok 149 | doAssert zeroEmpty + -bigOne == -bigOne # ok 150 | doAssert -zeroEmpty + -bigOne == -bigOne # ok 151 | 152 | # proc unsignedSubtraction(a: var BigInt, b, c: BigInt) 153 | doAssert zeroEmpty - one == -one # ok 154 | doAssert one - zeroEmpty == one # ok 155 | doAssert -zeroEmpty - one == -one # ok 156 | doAssert one - -zeroEmpty == one # ok 157 | doAssert zeroEmpty - zeroEmpty == zero # ok 158 | doAssert -zeroEmpty - zeroEmpty == zero # ok 159 | doAssert -zeroEmpty - -zeroEmpty == zero # ok 160 | doAssert zeroEmpty - -zeroEmpty == zero # ok 161 | doAssert bigOne - zeroEmpty == bigOne # ok 162 | doAssert bigOne - -zeroEmpty == bigOne # ok 163 | doAssert zeroEmpty - bigOne == -bigOne # ok 164 | doAssert -zeroEmpty - bigOne == -bigOne # ok 165 | doAssert -bigOne - zeroEmpty == -bigOne # ok 166 | doAssert -bigOne - -zeroEmpty == -bigOne # ok 167 | doAssert zeroEmpty - -bigOne == bigOne # ok 168 | doAssert -zeroEmpty - -bigOne == bigOne # ok 169 | 170 | # multiplication 171 | doAssert zeroEmpty * one == zero 172 | doAssert -zeroEmpty * one == zero 173 | doAssert one * zeroEmpty == zero 174 | doAssert one * -zeroEmpty == zero 175 | 176 | # division does not have issues, but let's add some doAsserts 177 | doAssert zeroEmpty div one == zero 178 | doAssert -zeroEmpty div one == zero 179 | doAssert zeroEmpty mod one == zero 180 | doAssert -zeroEmpty mod one == zero 181 | 182 | # toInt 183 | for z in [zero, zeroEmpty, -zero, -zeroEmpty]: 184 | doAssert toInt[int](z) == some(0) 185 | doAssert toInt[int8](z) == some(0'i8) 186 | doAssert toInt[int16](z) == some(0'i16) 187 | doAssert toInt[int32](z) == some(0'i32) 188 | doAssert toInt[int64](z) == some(0'i64) 189 | doAssert toInt[uint](z) == some(0'u) 190 | doAssert toInt[uint8](z) == some(0'u8) 191 | doAssert toInt[uint16](z) == some(0'u16) 192 | doAssert toInt[uint32](z) == some(0'u32) 193 | doAssert toInt[uint64](z) == some(0'u64) 194 | 195 | block: # addition/subtraction 196 | block: # self-addition/self-subtraction 197 | # self-addition 198 | var a = zero 199 | a += a 200 | doAssert a == zero 201 | a = 12.initBigInt 202 | a += a 203 | doAssert a == 24.initBigInt 204 | a = 20736.initBigInt 205 | a += a 206 | doAssert a == 41472.initBigInt 207 | a = "184884258895036416".initBigInt 208 | a += a 209 | doAssert a == "369768517790072832".initBigInt 210 | 211 | # self-subtraction 212 | var b = zero 213 | b -= b 214 | doAssert b == zero 215 | b = 12.initBigInt 216 | b -= b 217 | doAssert b == zero 218 | b = 20736.initBigInt 219 | b -= b 220 | doAssert b == zero 221 | b = "184884258895036416".initBigInt 222 | b -= b 223 | doAssert b == zero 224 | 225 | block: # multiplication 226 | block: 227 | let 228 | a = "1780983279228119273110576463639172624".initBigInt 229 | b = "1843917749452418885995463656480858321".initBigInt 230 | c = "3283986680046702618742503890385314117448805445290098330749803441805804304".initBigInt 231 | doAssert a * b == c 232 | doAssert -a * b == -c 233 | doAssert a * -b == -c 234 | doAssert -a * -b == c 235 | 236 | block: # self-multiplication 237 | var a = 12.initBigInt 238 | a *= a 239 | doAssert a == 144.initBigInt 240 | a *= a 241 | doAssert a == 20736.initBigInt 242 | a *= a 243 | doAssert a == 429981696.initBigInt 244 | a *= a 245 | doAssert a == "184884258895036416".initBigInt 246 | var b = zero 247 | b *= b 248 | doAssert b == zero 249 | var c = one 250 | c *= c 251 | doAssert c == one 252 | a *= b 253 | doAssert a == zero 254 | 255 | block: # shift 256 | let 257 | x = "190485713846014693847".initBigInt 258 | y = "-190485713846014693847".initBigInt 259 | a63 = "9223372036854775808".initBigInt 260 | a64 = "18446744073709551616".initBigInt 261 | a65 = "36893488147419103232".initBigInt 262 | a128 = "340282366920938463463374607431768211456".initBigInt 263 | 264 | # shl 265 | doAssert one shl 63 == a63 266 | doAssert one shl 64 == a64 267 | doAssert one shl 65 == a65 268 | doAssert one shl 128 == a128 269 | doAssert x shl 0 == x 270 | doAssert x shl 1 == "380971427692029387694".initBigInt 271 | doAssert x shl 7 == "24382171372289880812416".initBigInt 272 | doAssert x shl 31 == "409064955661923745004158713856".initBigInt 273 | doAssert x shl 32 == "818129911323847490008317427712".initBigInt 274 | doAssert x shl 33 == "1636259822647694980016634855424".initBigInt 275 | doAssert x shl 53 == "1715742779792629411365922910161076224".initBigInt 276 | doAssert x shl 63 == "1756920606507652517238705060004942053376".initBigInt 277 | doAssert x shl 64 == "3513841213015305034477410120009884106752".initBigInt 278 | doAssert x shl 65 == "7027682426030610068954820240019768213504".initBigInt 279 | doAssert y shl 0 == y 280 | doAssert y shl 1 == "-380971427692029387694".initBigInt 281 | doAssert y shl 7 == "-24382171372289880812416".initBigInt 282 | doAssert y shl 31 == "-409064955661923745004158713856".initBigInt 283 | doAssert y shl 32 == "-818129911323847490008317427712".initBigInt 284 | doAssert y shl 33 == "-1636259822647694980016634855424".initBigInt 285 | doAssert y shl 53 == "-1715742779792629411365922910161076224".initBigInt 286 | doAssert y shl 63 == "-1756920606507652517238705060004942053376".initBigInt 287 | doAssert y shl 64 == "-3513841213015305034477410120009884106752".initBigInt 288 | doAssert y shl 65 == "-7027682426030610068954820240019768213504".initBigInt 289 | 290 | # shr 291 | doAssert a63 shr 63 == one 292 | doAssert a64 shr 64 == one 293 | doAssert a65 shr 65 == one 294 | doAssert a128 shr 128 == one 295 | doAssert -one shr 1 == -one 296 | doAssert -2.initBigInt shr 1 == -one 297 | doAssert x shr 0 == x 298 | doAssert x shr 1 == "95242856923007346923".initBigInt 299 | doAssert x shr 7 == "1488169639421989795".initBigInt 300 | doAssert x shr 31 == "88701822723".initBigInt 301 | doAssert x shr 32 == "44350911361".initBigInt 302 | doAssert x shr 33 == "22175455680".initBigInt 303 | doAssert x shr 53 == "21148".initBigInt 304 | doAssert x shr 63 == "20".initBigInt 305 | doAssert x shr 64 == "10".initBigInt 306 | doAssert x shr 65 == "5".initBigInt 307 | doAssert y shr 0 == y 308 | doAssert y shr 1 == "-95242856923007346924".initBigInt 309 | doAssert y shr 7 == "-1488169639421989796".initBigInt 310 | doAssert y shr 31 == "-88701822724".initBigInt 311 | doAssert y shr 32 == "-44350911362".initBigInt 312 | doAssert y shr 33 == "-22175455681".initBigInt 313 | doAssert y shr 53 == "-21149".initBigInt 314 | doAssert y shr 63 == "-21".initBigInt 315 | doAssert y shr 64 == "-11".initBigInt 316 | doAssert y shr 65 == "-6".initBigInt 317 | 318 | block: # bitwise operations 319 | let 320 | a = "123456789123456789123456789".initBigInt 321 | b = 567.initBigInt 322 | c = 1234.initBigInt 323 | d = "340282366920938463463374607431768211456".initBigInt 324 | e = 1.initBigInt 325 | f = 0.initBigInt 326 | 327 | block: # not 328 | let testCases = [ 329 | (a, "-123456789123456789123456790".initBigInt), 330 | (b, -568.initBigInt), 331 | (c, -1235.initBigInt), 332 | (d, "-340282366920938463463374607431768211457".initBigInt), 333 | (e, -2.initBigInt), 334 | (f, -1.initBigInt), 335 | ] 336 | for (x, y) in testCases: 337 | doAssert (not x) == y 338 | doAssert (not y) == x 339 | 340 | block: # and 341 | doAssert (a and b) == 533.initBigInt 342 | doAssert (a and c) == 1040.initBigInt 343 | doAssert (b and c) == 18.initBigInt 344 | doAssert (a and d) == 0.initBigInt 345 | doAssert (b and d) == 0.initBigInt 346 | doAssert (a and e) == 1.initBigInt 347 | doAssert (d and e) == 0.initBigInt 348 | 349 | doAssert (a and (not b)) == "123456789123456789123456256".initBigInt 350 | doAssert (a and (not c)) == "123456789123456789123455749".initBigInt 351 | doAssert (b and (not c)) == 549.initBigInt 352 | doAssert (a and (not d)) == "123456789123456789123456789".initBigInt 353 | doAssert (b and (not d)) == 567.initBigInt 354 | doAssert (a and (not e)) == "123456789123456789123456788".initBigInt 355 | doAssert (d and (not e)) == d 356 | 357 | doAssert ((not a) and b) == 34.initBigInt 358 | doAssert ((not a) and c) == 194.initBigInt 359 | doAssert ((not b) and c) == 1216.initBigInt 360 | doAssert ((not a) and d) == "340282366920938463463374607431768211456".initBigInt 361 | doAssert ((not b) and d) == "340282366920938463463374607431768211456".initBigInt 362 | doAssert ((not a) and e) == 0.initBigInt 363 | doAssert ((not d) and e) == 1.initBigInt 364 | 365 | doAssert ((not a) and (not b)) == "-123456789123456789123456824".initBigInt 366 | doAssert ((not a) and (not c)) == "-123456789123456789123456984".initBigInt 367 | doAssert ((not b) and (not c)) == -1784.initBigInt 368 | doAssert ((not a) and (not d)) == "-340282366921061920252498064220891668246".initBigInt 369 | doAssert ((not b) and (not d)) == "-340282366920938463463374607431768212024".initBigInt 370 | doAssert ((not a) and (not e)) == "-123456789123456789123456790".initBigInt 371 | doAssert ((not d) and (not e)) == "-340282366920938463463374607431768211458".initBigInt 372 | 373 | block: # or 374 | doAssert (a or b) == "123456789123456789123456823".initBigInt 375 | doAssert (a or c) == "123456789123456789123456983".initBigInt 376 | doAssert (b or c) == 1783.initBigInt 377 | doAssert (a or d) == "340282366921061920252498064220891668245".initBigInt 378 | doAssert (b or d) == "340282366920938463463374607431768212023".initBigInt 379 | doAssert (a or e) == a 380 | doAssert (d or e) == (d + e) 381 | 382 | doAssert (a or (not b)) == -35.initBigInt 383 | doAssert (a or (not c)) == -195.initBigInt 384 | doAssert (b or (not c)) == -1217.initBigInt 385 | doAssert (a or (not d)) == "-340282366920938463463374607431768211457".initBigInt 386 | doAssert (b or (not d)) == "-340282366920938463463374607431768211457".initBigInt 387 | doAssert (a or (not e)) == -1.initBigInt 388 | doAssert (d or (not e)) == -2.initBigInt 389 | 390 | doAssert ((not a) or b) == "-123456789123456789123456257".initBigInt 391 | doAssert ((not a) or c) == "-123456789123456789123455750".initBigInt 392 | doAssert ((not b) or c) == -550.initBigInt 393 | doAssert ((not a) or d) == "-123456789123456789123456790".initBigInt 394 | doAssert ((not b) or d) == -568.initBigInt 395 | doAssert ((not a) or e) == "-123456789123456789123456789".initBigInt 396 | doAssert ((not d) or e) == "-340282366920938463463374607431768211457".initBigInt 397 | 398 | doAssert ((not a) or (not b)) == -534.initBigInt 399 | doAssert ((not a) or (not c)) == -1041.initBigInt 400 | doAssert ((not b) or (not c)) == -19.initBigInt 401 | doAssert ((not a) or (not d)) == -1.initBigInt 402 | doAssert ((not b) or (not d)) == -1.initBigInt 403 | doAssert ((not a) or (not e)) == -2.initBigInt 404 | doAssert ((not d) or (not e)) == -1.initBigInt 405 | 406 | block: # xor 407 | doAssert (a xor b) == "123456789123456789123456290".initBigInt 408 | doAssert (a xor c) == "123456789123456789123455943".initBigInt 409 | doAssert (b xor c) == 1765.initBigInt 410 | doAssert (a xor d) == "340282366921061920252498064220891668245".initBigInt 411 | doAssert (b xor d) == "340282366920938463463374607431768212023".initBigInt 412 | doAssert (a xor e) == (a - e) 413 | doAssert (d xor e) == (d + e) 414 | doAssert (d xor d) == f 415 | doAssert (d xor f) == d 416 | 417 | doAssert (a xor (not b)) == "-123456789123456789123456291".initBigInt 418 | doAssert (a xor (not c)) == "-123456789123456789123455944".initBigInt 419 | doAssert (b xor (not c)) == -1766.initBigInt 420 | doAssert (a xor (not d)) == "-340282366921061920252498064220891668246".initBigInt 421 | doAssert (b xor (not d)) == "-340282366920938463463374607431768212024".initBigInt 422 | doAssert (a xor (not e)) == "-123456789123456789123456789".initBigInt 423 | doAssert (d xor (not e)) == "-340282366920938463463374607431768211458".initBigInt 424 | doAssert (d xor (not d)) == -1.initBigInt 425 | doAssert (d xor (not f)) == (not d) 426 | 427 | doAssert ((not a) xor b) == "-123456789123456789123456291".initBigInt 428 | doAssert ((not a) xor c) == "-123456789123456789123455944".initBigInt 429 | doAssert ((not b) xor c) == -1766.initBigInt 430 | doAssert ((not a) xor d) == "-340282366921061920252498064220891668246".initBigInt 431 | doAssert ((not b) xor d) == "-340282366920938463463374607431768212024".initBigInt 432 | doAssert ((not a) xor e) == "-123456789123456789123456789".initBigInt 433 | doAssert ((not d) xor e) == "-340282366920938463463374607431768211458".initBigInt 434 | doAssert ((not d) xor d) == -1.initBigInt 435 | doAssert ((not d) xor f) == (not d) 436 | 437 | doAssert ((not a) xor (not b)) == "123456789123456789123456290".initBigInt 438 | doAssert ((not a) xor (not c)) == "123456789123456789123455943".initBigInt 439 | doAssert ((not b) xor (not c)) == 1765.initBigInt 440 | doAssert ((not a) xor (not d)) == "340282366921061920252498064220891668245".initBigInt 441 | doAssert ((not b) xor (not d)) == "340282366920938463463374607431768212023".initBigInt 442 | doAssert ((not a) xor (not e)) == (a - e) 443 | doAssert ((not d) xor (not e)) == (d + e) 444 | doAssert ((not d) xor (not d)) == f 445 | doAssert ((not d) xor (not f)) == d 446 | 447 | block: # inc/dec 448 | var x: BigInt 449 | 450 | x = 42.initBigInt 451 | x.inc 452 | doAssert x == 43.initBigInt 453 | x.inc(int32.high) 454 | doAssert x == "2147483690".initBigInt 455 | x.inc(int32.low) 456 | doAssert x == 42.initBigInt 457 | x.inc(-42) 458 | doAssert x == 0.initBigInt 459 | 460 | x = 42.initBigInt 461 | x.dec 462 | doAssert x == 41.initBigInt 463 | x.dec(int32.high) 464 | doAssert x == "-2147483606".initBigInt 465 | x.dec(int32.low) 466 | doAssert x == 42.initBigInt 467 | x.dec(-42) 468 | doAssert x == 84.initBigInt 469 | 470 | # edge cases 471 | 472 | x = 1.initBigInt 473 | x.inc(int32.low) 474 | doAssert x == "-2147483647".initBigInt 475 | x = -1.initBigInt 476 | x.inc(2) 477 | doAssert x == 1.initBigInt 478 | x = -1.initBigInt 479 | x.inc(-2) 480 | doAssert x == -3.initBigInt 481 | 482 | x = 0.initBigInt 483 | x.dec(int32.low) 484 | doAssert x == "2147483648".initBigInt 485 | x = 1.initBigInt 486 | x.dec(-2) 487 | doAssert x == 3.initBigInt 488 | x = -1.initBigInt 489 | x.dec(-2) 490 | doAssert x == 1.initBigInt 491 | x = 12.initBigInt 492 | x.dec(42) 493 | doAssert x == -30.initBigInt 494 | 495 | when sizeof(int) == 8: 496 | # int has 64 bits 497 | x = 42.initBigInt 498 | x.inc(int32.high.int + 1) 499 | doAssert x == "2147483690".initBigInt 500 | x.inc(int64.high.int) 501 | doAssert x == "9223372039002259497".initBigInt 502 | x.inc(int32.low.int - 1) 503 | doAssert x == "9223372036854775848".initBigInt 504 | x.inc(int64.low.int) 505 | doAssert x == 40.initBigInt 506 | x.dec(int32.high.int + 1) 507 | doAssert x == "-2147483608".initBigInt 508 | x.dec(int64.high.int) 509 | doAssert x == "-9223372039002259415".initBigInt 510 | x.dec(int32.low.int - 1) 511 | doAssert x == "-9223372036854775766".initBigInt 512 | x.dec(int64.low.int) 513 | doAssert x == 42.initBigInt 514 | 515 | block: # string conversion 516 | for base in 2..36: 517 | # zero 518 | doAssert zero.toString(base) == "0" 519 | doAssert (-zero).toString(base) == "0" # no sign is produced for 0 520 | doAssert "0".initBigInt(base) == zero 521 | doAssert "-0".initBigInt(base) == zero 522 | doAssert "00000".initBigInt(base) == zero 523 | doAssert "-00000".initBigInt(base) == zero 524 | doAssert "00000000000000000000000000000000000".initBigInt(base) == zero 525 | doAssert "-00000000000000000000000000000000000".initBigInt(base) == zero 526 | 527 | # one 528 | doAssert one.toString(base) == "1" 529 | doAssert (-one).toString(base) == "-1" 530 | doAssert "1".initBigInt(base) == one 531 | doAssert "-1".initBigInt(base) == -one 532 | doAssert "00001".initBigInt(base) == one 533 | doAssert "-00001".initBigInt(base) == -one 534 | doAssert "00000000000000000000000000000000001".initBigInt(base) == one 535 | doAssert "-00000000000000000000000000000000001".initBigInt(base) == -one 536 | 537 | let a = initBigInt(uint64(uint32.high) + 1) 538 | doAssert a.toString(base = 2) == "100000000000000000000000000000000" 539 | doAssert a.toString(base = 3) == "102002022201221111211" 540 | doAssert a.toString(base = 4) == "10000000000000000" 541 | doAssert a.toString(base = 8) == "40000000000" 542 | doAssert a.toString(base = 10) == "4294967296" 543 | doAssert a.toString(base = 12) == "9ba461594" 544 | doAssert a.toString(base = 16) == "100000000" 545 | doAssert a.toString(base = 32) == "4000000" 546 | 547 | let b = initBigInt(0xfedcba9876543210'u64) 548 | doAssert "1111111011011100101110101001100001110110010101000011001000010000".initBigInt(base = 2) == b 549 | doAssert "11112100120110012201202221111221022102200".initBigInt(base = 3) == b 550 | doAssert "33323130232221201312111003020100".initBigInt(base = 4) == b 551 | doAssert "1773345651416625031020".initBigInt(base = 8) == b 552 | doAssert "18364758544493064720".initBigInt(base = 10) == b 553 | doAssert "833b81a74046633500".initBigInt(base = 12) == b 554 | doAssert "fedcba9876543210".initBigInt(base = 16) == b 555 | doAssert "ftn5qj1r58cgg".initBigInt(base = 32) == b 556 | 557 | block: # fastLog2 558 | let a = one shl 31 559 | let b = a shl 1 560 | let c = initBigInt(0xfedcba9876543210'u64) 561 | let d = initBigInt("ffffffffffffffffff", base = 16) 562 | 563 | # first numbers 564 | doAssert fastLog2(2.initBigInt) == 1 565 | doAssert fastLog2(3.initBigInt) == 1 566 | doAssert fastLog2(4.initBigInt) == 2 567 | doAssert fastLog2(5.initBigInt) == 2 568 | doAssert fastLog2(7.initBigInt) == 2 569 | doAssert fastLog2(8.initBigInt) == 3 570 | doAssert fastLog2(24.initBigInt) == 4 571 | doAssert fastLog2(32.initBigInt) == 5 572 | doAssert fastLog2(48.initBigInt) == 5 573 | 574 | # one limb 575 | doAssert fastLog2(a) == 31 576 | 577 | # two limbs and more 578 | doAssert fastLog2(b) == 32 579 | doAssert fastLog2(b+a) == 32 580 | doAssert fastLog2(c+b+a) == 63 581 | 582 | doAssert fastLog2(d) == 71 583 | doAssert fastLog2(d + one) == 72 584 | doAssert fastLog2(d - one) == 71 585 | doAssert fastLog2(-d) == 71 586 | doAssert fastLog2(-d - one) == 72 587 | doAssert fastLog2(-d + one) == 71 588 | 589 | # negative BigInts 590 | doAssert fastLog2(-2.initBigInt) == 1 591 | doAssert fastLog2(-3.initBigInt) == 1 592 | doAssert fastLog2(-4.initBigInt) == 2 593 | doAssert fastLog2(-5.initBigInt) == 2 594 | doAssert fastLog2(-7.initBigInt) == 2 595 | doAssert fastLog2(-8.initBigInt) == 3 596 | doAssert fastLog2(-24.initBigInt) == 4 597 | doAssert fastLog2(-32.initBigInt) == 5 598 | doAssert fastLog2(-48.initBigInt) == 5 599 | doAssert fastLog2(-a) == 31 600 | doAssert fastLog2(-b) == 32 601 | 602 | # edge cases 603 | doAssert fastLog2(one) == 0 604 | doAssert fastLog2(zero) == -1 605 | 606 | 607 | block: # pow 608 | let a = "14075287".initBigInt 609 | doAssert pow(a, 0) == one 610 | doAssert pow(a, 1) == a 611 | doAssert pow(a, 2) == a * a 612 | doAssert pow(a, 3) == a * a * a 613 | doAssert pow(a, 4) == a * a * a * a 614 | doAssert pow(a, 5) == a * a * a * a * a 615 | doAssert pow(a, 6) == a * a * a * a * a * a 616 | doAssert pow(a, 7) == a * a * a * a * a * a * a 617 | 618 | # special cases 619 | doAssert pow(zero, 0) == one 620 | doAssert pow(zero, 1) == zero 621 | 622 | block: # invmod 623 | # with prime modulus 624 | let a = "30292868".initBigInt 625 | let b = "48810860".initBigInt 626 | let p = "60449131".initBigInt # p is prime 627 | doAssert invmod(a, p) == "51713091".initBigInt 628 | doAssert invmod(-b, p) == "31975542".initBigInt 629 | # with composite modulus 630 | let c = "2472018".initBigInt 631 | let n = "3917515".initBigInt # 5 * 7 * 19 * 43 * 137 632 | let d = "1831482".initBigInt 633 | let e = "2502552".initBigInt 634 | let f = "2086033".initBigInt 635 | let h = "1414963".initBigInt 636 | doAssert invmod(c, n) == "2622632".initBigInt 637 | doAssert invmod(one, n) == one 638 | doAssert invmod(n-one, n) == n-one 639 | 640 | doAssert invmod( d, n) == h 641 | doAssert invmod(-d, n) == e 642 | doAssert invmod( f, n) == e 643 | doAssert invmod(-f, n) == h 644 | doAssert invmod( e, n) == f 645 | doAssert invmod(-e, n) == d 646 | doAssert invmod( h, n) == d 647 | doAssert invmod(-h, n) == f 648 | 649 | block: 650 | let 651 | a = "2147483647".initBigInt # M_31 mersenne prime 652 | b = "2147483649".initBigInt # a^-1 mod m 653 | m = "2305843009213693951".initBigInt # M_61 mersenne prime 654 | for x in [a - m - m, a - m, a, a + m, a + m + m]: 655 | doAssert invmod(x, m) == b 656 | for x in [b - m - m, b - m, b, b + m, b + m + m]: 657 | doAssert invmod(x, m) == a 658 | 659 | # exceptions 660 | doAssertRaises(DivByZeroDefect): discard invmod(zero, n) 661 | doAssertRaises(DivByZeroDefect): discard invmod(one, zero) 662 | doAssertRaises(ValueError): discard invmod(one, -7.initBigInt) 663 | doAssertRaises(ValueError): discard invmod(3.initBigInt, 18.initBigInt) # 3 is not invertible since gcd(3, 18) = 3 != 1 664 | for x in [-n - n, -n, n, n + n]: 665 | doAssertRaises(ValueError): discard invmod(x, n) # invmod(0, n) 666 | 667 | block: # https://rosettacode.org/wiki/Modular_inverse 668 | doAssert invmod(42.initBigInt, 2017.initBigInt) == 1969.initBigInt 669 | 670 | block: # powmod 671 | let a = "30292868".initBigInt 672 | let p = "60449131".initBigInt # p is prime 673 | let two = 2.initBigInt 674 | doAssert powmod(a, two, p) == "25760702".initBigInt 675 | # Fermat's little theorem: a^p ≡ a mod p 676 | doAssert powmod(a, p, p) == a 677 | # Euler's identity a^(p-1) \equiv 1 \bmod p 678 | doAssert powmod(a, p - one, p) == one 679 | # We can invert a using Euler's identity / Fermat's little theorem 680 | doAssert powmod(a, p - two, p) == "51713091".initBigInt 681 | # We can reduce the exponent modulo phi(p) = p - 1, since p is prime 682 | doAssert powmod(a, 2.initBigInt*p, p) == (a * a mod p) 683 | 684 | let p2 = 761.initBigInt 685 | var a2 = 1.initBigInt 686 | # Fermat's little theorem: a^p ≡ a mod p 687 | while a2 < p2: 688 | doAssert powmod(a2, p2, p2) == a2 689 | a2.inc 690 | 691 | block: # https://rosettacode.org/wiki/Modular_exponentiation 692 | let 693 | a = "2988348162058574136915891421498819466320163312926952423791023078876139".initBigInt 694 | b = "2351399303373464486466122544523690094744975233415544072992656881240319".initBigInt 695 | m = pow(10.initBigInt, 40) 696 | doAssert powmod(a, b, m) == "1527229998585248450016808958343740453059".initBigInt 697 | 698 | block: # Composite modulus 699 | let a = "2472018".initBigInt 700 | let n = "3917515".initBigInt # 5 * 7 * 19 * 43 * 137 701 | let euler_phi = "2467584".initBigInt 702 | doAssert powmod(a, 52.initBigInt, n) == "2305846".initBigInt 703 | doAssert powmod(a, euler_phi, n) == one 704 | # Edge cases 705 | doAssert powmod(a, one, n) == a 706 | doAssert powmod(a, zero, n) == one 707 | doAssert powmod(zero, zero, n) == one 708 | doAssert powmod(zero, one, n) == zero 709 | 710 | block: # powmod with negative base 711 | let a = "1986599".initBigInt 712 | let p = "10230581".initBigInt 713 | doAssert powmod(-a, 2.initBigInt, p) == "6199079".initBigInt 714 | 715 | block: # powmod with negative exponent 716 | let a = "1912".initBigInt 717 | let p = "5297".initBigInt 718 | doAssert powmod(a, -1.initBigInt, p) == "1460".initBigInt 719 | doAssert powmod(a, one-p, p) == one 720 | 721 | block: # div/mod 722 | doAssertRaises(DivByZeroDefect): discard one div zero 723 | doAssertRaises(DivByZeroDefect): discard one mod zero 724 | doAssertRaises(DivByZeroDefect): discard divmod(one, zero) 725 | 726 | block: # gcd 727 | let a = "866506".initBigInt 728 | let b = "140640".initBigInt 729 | let two = 2.initBigInt 730 | doAssert gcd(a, b) == two 731 | # gcd(a, b) = gcd(b, a) 732 | doAssert gcd(b, a) == two 733 | # gcd(a, -b) = gcd(a, |b|) 734 | doAssert gcd(-a, b) == two 735 | doAssert gcd(a, -b) == two 736 | doAssert gcd(-a, -b) == two 737 | 738 | block: # properties of gcd 739 | let a = "668403".initBigInt 740 | let b = "753160".initBigInt 741 | let c = "249115".initBigInt 742 | doAssert gcd(a, b) == gcd(b, a) 743 | doAssert gcd(a, zero) == a 744 | doAssert gcd(a, a) == a 745 | doAssert gcd(c * a, c * b) == c * gcd(a,b) 746 | doAssert gcd(a, gcd(b, c)) == gcd(gcd(a, b), c) 747 | doAssert gcd(a, b) == gcd(b, a mod b) 748 | 749 | block: # abs 750 | doAssert abs(zero) == zero 751 | doAssert abs(-zero) == zero 752 | doAssert abs(one) == one 753 | doAssert abs(-one) == one 754 | 755 | block: # toInt 756 | let 757 | a = initBigInt(7) 758 | b = initBigInt(-7) 759 | doAssert toInt[int8](a) == some(7'i8) 760 | doAssert toInt[int8](b) == some(-7'i8) 761 | doAssert toInt[uint8](a) == some(7'u8) 762 | doAssert toInt[uint8](b) == none(uint8) 763 | doAssert toInt[int16](a) == some(7'i16) 764 | doAssert toInt[int16](b) == some(-7'i16) 765 | doAssert toInt[uint16](a) == some(7'u16) 766 | doAssert toInt[uint16](b) == none(uint16) 767 | 768 | block: # int32 769 | let 770 | i32h = int32.high 771 | i32l = int32.low 772 | c = initBigInt(i32h) 773 | d = initBigInt(i32h - 1) 774 | e = initBigInt(int64(i32h) + 1) 775 | f = initBigInt(i32l) 776 | g = initBigInt(i32l + 1) 777 | h = initBigInt(int64(i32l) - 1) 778 | doAssert toInt[int8](c) == none(int8) 779 | doAssert toInt[int16](c) == none(int16) 780 | doAssert toInt[int32](c) == some(i32h) 781 | doAssert toInt[int](c) == some(i32h.int) 782 | doAssert toInt[int8](d) == none(int8) 783 | doAssert toInt[int16](d) == none(int16) 784 | doAssert toInt[int32](d) == some(i32h - 1) 785 | doAssert toInt[int](d) == some(i32h.int - 1) 786 | doAssert toInt[int8](e) == none(int8) 787 | doAssert toInt[int16](e) == none(int16) 788 | doAssert toInt[int32](e) == none(int32) 789 | doAssert toInt[int64](e) == some(i32h.int64 + 1) 790 | doAssert toInt[int8](f) == none(int8) 791 | doAssert toInt[int16](f) == none(int16) 792 | doAssert toInt[int32](f) == some(i32l) 793 | doAssert toInt[int](f) == some(i32l.int) 794 | doAssert toInt[int8](g) == none(int8) 795 | doAssert toInt[int16](g) == none(int16) 796 | doAssert toInt[int32](g) == some(i32l + 1) 797 | doAssert toInt[int](g) == some(i32l.int + 1) 798 | doAssert toInt[int8](h) == none(int8) 799 | doAssert toInt[int16](h) == none(int16) 800 | doAssert toInt[int32](h) == none(int32) 801 | doAssert toInt[int64](h) == some(i32l.int64 - 1) 802 | 803 | block: # uint32 804 | let 805 | u32h = uint32.high 806 | a = initBigInt(u32h) 807 | b = initBigInt(u32h - 1) 808 | c = initBigInt(uint64(u32h) + 1) 809 | doAssert toInt[uint8](a) == none(uint8) 810 | doAssert toInt[uint16](a) == none(uint16) 811 | doAssert toInt[uint32](a) == some(u32h) 812 | doAssert toInt[uint](a) == some(u32h.uint) 813 | doAssert toInt[uint8](b) == none(uint8) 814 | doAssert toInt[uint16](b) == none(uint16) 815 | doAssert toInt[uint32](b) == some(u32h - 1) 816 | doAssert toInt[uint](b) == some(u32h.uint - 1) 817 | doAssert toInt[uint8](c) == none(uint8) 818 | doAssert toInt[uint16](c) == none(uint16) 819 | doAssert toInt[uint32](c) == none(uint32) 820 | doAssert toInt[uint64](c) == some(u32h.uint64 + 1) 821 | 822 | block: # int64 823 | let 824 | i64h = int64.high 825 | i64l = int64.low 826 | i = initBigInt(i64h) 827 | j = initBigInt(i64h - 1) 828 | k = initBigInt(uint64(int64.high) + 1) 829 | l = initBigInt(i64l) 830 | m = initBigInt(i64l + 1) 831 | n = initBigInt(int64.low) - one 832 | doAssert toInt[int8](i) == none(int8) 833 | doAssert toInt[int16](i) == none(int16) 834 | doAssert toInt[int32](i) == none(int32) 835 | doAssert toInt[int64](i) == some(i64h) 836 | doAssert toInt[int8](j) == none(int8) 837 | doAssert toInt[int16](j) == none(int16) 838 | doAssert toInt[int32](j) == none(int32) 839 | doAssert toInt[int64](j) == some(i64h - 1) 840 | doAssert toInt[int8](k) == none(int8) 841 | doAssert toInt[int16](k) == none(int16) 842 | doAssert toInt[int32](k) == none(int32) 843 | doAssert toInt[int64](k) == none(int64) 844 | doAssert toInt[int8](l) == none(int8) 845 | doAssert toInt[int16](l) == none(int16) 846 | doAssert toInt[int32](l) == none(int32) 847 | doAssert toInt[int64](l) == some(i64l) 848 | doAssert toInt[int8](m) == none(int8) 849 | doAssert toInt[int16](m) == none(int16) 850 | doAssert toInt[int32](m) == none(int32) 851 | doAssert toInt[int64](m) == some(i64l + 1) 852 | doAssert toInt[int8](n) == none(int8) 853 | doAssert toInt[int16](n) == none(int16) 854 | doAssert toInt[int32](n) == none(int32) 855 | doAssert toInt[int64](n) == none(int64) 856 | 857 | block: # uint64 858 | let 859 | u64h = uint64.high 860 | a = initBigInt(u64h) 861 | b = initBigInt(u64h - 1) 862 | c = initBigInt(uint64.high) + one 863 | doAssert toInt[uint8](a) == none(uint8) 864 | doAssert toInt[uint16](a) == none(uint16) 865 | doAssert toInt[uint32](a) == none(uint32) 866 | doAssert toInt[uint64](a) == some(u64h) 867 | doAssert toInt[uint8](b) == none(uint8) 868 | doAssert toInt[uint16](b) == none(uint16) 869 | doAssert toInt[uint32](b) == none(uint32) 870 | doAssert toInt[uint64](b) == some(u64h - 1) 871 | doAssert toInt[uint8](c) == none(uint8) 872 | doAssert toInt[uint16](c) == none(uint16) 873 | doAssert toInt[uint32](c) == none(uint32) 874 | doAssert toInt[uint64](c) == none(uint64) 875 | 876 | block: # pred/succ 877 | let a = initBigInt(7) 878 | doAssert pred(a) == initBigInt(6) 879 | doAssert succ(a) == initBigInt(8) 880 | doAssert pred(a, 3) == initBigInt(4) 881 | doAssert succ(a, 3) == initBigInt(10) 882 | 883 | 884 | static: main() 885 | main() 886 | -------------------------------------------------------------------------------- /tests/tbugs.nim: -------------------------------------------------------------------------------- 1 | import std/options 2 | import bigints 3 | 4 | proc main() = 5 | block: # range of BigInt (https://github.com/nim-lang/bigints/issues/1) 6 | let two = 2.initBigInt 7 | let n = "123".initBigInt 8 | var result = 1.initBigInt 9 | for i in two .. n: 10 | result *= i 11 | doAssert result == initBigInt("12146304367025329675766243241881295855454217088483382315328918161829235892362167668831156960612640202170735835221294047782591091570411651472186029519906261646730733907419814952960000000000000000000000000000") 12 | 13 | block: # multiple multiplications (https://github.com/nim-lang/bigints/issues/3) 14 | let nums = [ 15 | "68855123440532288245010625", 16 | "201850901852714536181760000", 17 | "435980903974422631450250625", 18 | "824199001261152424427520000", 19 | "11527258048987096618327125", 20 | "18960243520191483654144000", 21 | ] 22 | 23 | var total = 1.initBigInt 24 | 25 | for e in items(nums): 26 | let bigInt = e.initBigInt 27 | total *= bigInt 28 | 29 | doAssert total == initBigInt("1091531901753858845417645933677882391421406095571139520376889755608568225321090455009925801178698945969179844505331560015898829746339840000000000000000000000") 30 | 31 | block: # "negative BigInt (https://github.com/nim-lang/bigints/issues/4) 32 | let x = -initBigInt(1) 33 | doAssert x == initBigInt(-1) 34 | 35 | block: # off by one in division (https://github.com/nim-lang/bigints/issues/5) 36 | block: 37 | var x = initBigInt("815915283247897734345611269596115894272000000000") 38 | var y = initBigInt("5919012181389927685417441689600000000") 39 | doAssert x div y == initBigInt("137846528820") 40 | 41 | block: 42 | var x = initBigInt("815915283247897734345611269596115894272000000000") 43 | var y = initBigInt("20000000000") 44 | doAssert x div y == initBigInt("40795764162394886717280563479805794713") 45 | 46 | block: # negative zero flags (https://github.com/nim-lang/bigints/issues/16) 47 | let 48 | a = initBigInt("828478292990482") 49 | b = initBigInt(9283) 50 | c = initBigInt("-828478292990482") 51 | d = initBigInt(-9283) 52 | e = initBigInt(0) 53 | doAssert b + d == e 54 | doAssert a + c == e 55 | 56 | doAssert d + b == e 57 | doAssert c + a == e 58 | 59 | doAssert b - b == e 60 | doAssert d - d == e 61 | 62 | doAssert d * e == e 63 | doAssert b * e == e 64 | doAssert e div d == e 65 | 66 | block: # validate digits in string parsing (https://github.com/nim-lang/bigints/issues/24) 67 | doAssert initBigInt("1", 2) == initBigInt(1) 68 | doAssert initBigInt("z", 36) == initBigInt(35) 69 | doAssertRaises(ValueError): 70 | discard initBigInt("2", 2) 71 | doAssertRaises(ValueError): 72 | discard initBigInt("z", 35) 73 | 74 | block: # empty limbs when uninitialized (https://github.com/nim-lang/bigints/issues/26) 75 | var a: BigInt 76 | let b = 12.initBigInt 77 | 78 | doAssert a * b == 0.initBigInt 79 | 80 | block: # IndexError with a = a + b (https://github.com/nim-lang/bigints/issues/27) 81 | var 82 | a = 0.initBigInt 83 | b = "359097073186387306".initBigInt 84 | 85 | a = a + b # Error: unhandled exception: index out of bounds, the container is empty [IndexError] 86 | 87 | block: # toInt[int64] produces wrong results in certain cases (https://github.com/nim-lang/bigints/issues/99) 88 | doAssert toInt[int64](-initBigInt(0xFFFFFFFF_00000000'u64)) == none(int64) 89 | 90 | static: main() 91 | main() 92 | -------------------------------------------------------------------------------- /tests/tliterals.nim: -------------------------------------------------------------------------------- 1 | # This is an include file, do not import it directly. 2 | # This is needed as a workaround for Nim's parser for versions <= 1.4. 3 | 4 | let aa = 1234567'bi 5 | doAssert $aa == "1234567" 6 | 7 | let bb = -1234567'bi 8 | doAssert $bb == "-1234567" 9 | 10 | let cc = 123456789012345678'bi 11 | doAssert $cc == "123456789012345678" 12 | 13 | let dd = -123456789012345678'bi 14 | doAssert $dd == "-123456789012345678" 15 | 16 | let hh = 1234567'bi 17 | let ii = hh.initBigInt 18 | doAssert $hh == $ii 19 | 20 | let j = 0xff00'bi 21 | doAssert $j == "65280" 22 | let k = 0b1010101010101010101010101010101010101010'bi 23 | doAssert $k == "733007751850" 24 | let l = 0X123456789ABCDEF'bi 25 | doAssert $l == "81985529216486895" 26 | 27 | -------------------------------------------------------------------------------- /tests/trandom.nim: -------------------------------------------------------------------------------- 1 | import bigints 2 | import bigints/random 3 | import std/options 4 | 5 | block: # check uniformity 6 | let lo = pow(10.initBigInt, 90) 7 | let hi = pow(10.initBigInt, 100) 8 | var total = 0.initBigInt 9 | let trials = 1000 10 | let nbuckets = 33 11 | var buckets = newSeq[int](nbuckets) 12 | for x in 0..trials: 13 | let r = rand(lo..hi) 14 | doAssert(lo <= r) 15 | doAssert(r <= hi) 16 | total += r 17 | let iBucket = (r-lo) div ((hi-lo) div initBigInt(nbuckets)) 18 | buckets[iBucket.toInt[:int]().get()] += 1 19 | for x in buckets: 20 | doAssert(trials/nbuckets*0.5 < float(x)) 21 | doAssert(float(x) < trials/nbuckets*1.5) 22 | 23 | --------------------------------------------------------------------------------