Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and test initRandomBigInt for issue #101 #112

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion bigints.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ task test, "Test bigints":
echo "testing " & backend & " backend"
for gc in ["refc", "arc", "orc"]:
echo " using " & gc & " GC"
for file in ["tbigints.nim", "tbugs.nim"]:
for file in ["trandom.nim", "tbigints.nim", "tbugs.nim"]:
exec "nim r --hints:off --experimental:strictFuncs --backend:" & backend & " --gc:" & gc & " tests/" & file
exec "nim doc --hints:off --backend:" & backend & " --gc:" & gc & " src/bigints.nim"

Expand Down
24 changes: 23 additions & 1 deletion src/bigints.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Arbitrary precision integers.

import std/[algorithm, bitops, math, options]
import std/[algorithm, bitops, math, options, random]

type
BigInt* = object
Expand Down Expand Up @@ -66,6 +66,27 @@ else:
func initBigInt*(val: BigInt): BigInt =
result = val

proc initRandomBigInt*(nbits: Natural): BigInt =
## Initializes a standalone BigInt with exactly `nbits` bits.
let
remainder = nbits mod 32
n_limbs = (if remainder == 0: nbits shr 5 else: nbits shr 5 + 1)
remainingBits = (if remainder == 0: 32 else: remainder)
result.limbs.setLen(n_limbs)

# mask ensures only remainingBits bits can be set to 1
# Ensures the first bit is set to 1
dlesnoff marked this conversation as resolved.
Show resolved Hide resolved
var
mask: uint32 = 0xFFFF_FFFF'u32
mask2: uint32 = 0x8000_0000'u32
if remainingBits != 32:
mask = 1'u32 shl remainingBits - 1
mask2 = 1'u32 shl (remainingBits-1)
for i in 0 ..< result.limbs.len-1:
result.limbs[i] = rand(uint32)
let word = rand(uint32)
result.limbs[result.limbs.len-1] = word and mask or mask2

const
zero = initBigInt(0)
one = initBigInt(1)
Expand Down Expand Up @@ -1198,3 +1219,4 @@ func powmod*(base, exponent, modulus: BigInt): BigInt =
result = (result * basePow) mod modulus
basePow = (basePow * basePow) mod modulus
exponent = exponent shr 1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

There already is a trailing newline, isn't there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No there is not!
I added one, It makes the code fits better in the buffer.

18 changes: 18 additions & 0 deletions tests/trandom.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import bigints
import random

const
zero = initBigInt(0)
one = initBigInt(1)
dlesnoff marked this conversation as resolved.
Show resolved Hide resolved

proc main() =
block:
randomize()
# Repeat probabilistic tests
dlesnoff marked this conversation as resolved.
Show resolved Hide resolved
for nBits in [29, 32, 1037]:
dlesnoff marked this conversation as resolved.
Show resolved Hide resolved
for _ in 1 .. 5:
let a: BigInt = initRandomBigInt(nBits)
assert (toString(a, 2)).len == nBits
doAssert fastLog2(a) == (nBits - 1)
dlesnoff marked this conversation as resolved.
Show resolved Hide resolved

main()