-
Notifications
You must be signed in to change notification settings - Fork 30
Add and test initRandomBigInt for issue #101 #112
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
base: master
Are you sure you want to change the base?
Changes from 3 commits
49a7817
b4a1beb
87b1af3
682af3d
bbaa414
c23a6c4
5063ca3
a4ae17f
f54aba1
8d152ba
50ba335
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||||||||||
|
@@ -66,6 +66,50 @@ else: | |||||||||
func initBigInt*(val: BigInt): BigInt = | ||||||||||
result = val | ||||||||||
|
||||||||||
type | ||||||||||
SizeDescriptor* = enum | ||||||||||
Limbs, Bits | ||||||||||
|
||||||||||
proc initRandomBigInt*(number: Natural, unit: SizeDescriptor = Limbs): BigInt = | ||||||||||
## Initializes a standalone BigInt whose value is chosen randomly with exactly | ||||||||||
## `number` bits or limbs, depending on the value of `unit`. By default, the | ||||||||||
## BigInt is chosen with `number` limbs chosen randomly. | ||||||||||
dlesnoff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
if unit == Limbs: | ||||||||||
|
||||||||||
if number == 0: | ||||||||||
raise newException(ValueError, "A Bigint must have at least one limb !") | ||||||||||
|
||||||||||
result.limbs.setLen(number) | ||||||||||
for i in 0 ..< result.limbs.len-1: | ||||||||||
|
for i in 0 ..< result.limbs.len-1: | |
for i in 0 ..< result.limbs.high: |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result.limbs[result.limbs.len-1] = word | |
result.limbs[result.limbs.high] = word |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remainder = number mod 32 | |
n_limbs = (if remainder == 0: number shr 5 else: number shr 5 + 1) | |
remainder = number shr 5 | |
n_limbs = (if remainder == 0: remainder else: remainder + 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may add a variable for number shr 5 called quotient.
number mod 32 and number shr 5 does not do the same thing!
You changed the remainder definition but not the equality assertion with remainder.
I think you misunderstood these lines, I didn't get your changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, number shr 5
is number div 32
. But number mod 32
can be turned into number and 31
(which may or may not help, depending on if that optimization is already done).
dlesnoff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
dlesnoff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There already is a trailing newline, isn't there?
There was a problem hiding this comment.
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.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import bigints | ||
import random | ||
|
||
type | ||
MemSizeUnit = enum | ||
o, Kio, Mio, Gio | ||
|
||
const | ||
zero = initBigInt(0) | ||
one = initBigInt(1) | ||
dlesnoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
memSize = 2 # Max number of allocated memory for the tests | ||
memSizeUnit = Mio # Unit in which memSize is expressed | ||
|
||
proc computeLimit(memSize: Natural, memSizeUnit: MemSizeUnit): Natural = | ||
var factor = 1 | ||
for _ in 1..ord(memSizeUnit): | ||
factor *= 1024 | ||
result = memSize * factor | ||
dlesnoff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
const | ||
memLimit = computeLimit(memSize, memSizeUnit) # Number of octets | ||
dlesnoff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
maxLimbs = memLimit div 8 | ||
maxBits = 4*memLimit | ||
|
||
proc main() = | ||
randomize() | ||
|
||
block: | ||
let a: BigInt = initRandomBigInt(0, Bits) | ||
doAssert a == zero | ||
let b: BigInt = initRandomBigInt(1, Bits) | ||
doAssert b == one | ||
|
||
block: | ||
for nBits in [29, 32, 1037]: | ||
dlesnoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for _ in 1 .. 5: # Repeat probabilistic tests | ||
let a: BigInt = initRandomBigInt(nBits, Bits) | ||
doAssert fastLog2(a) == (nBits - 1) | ||
doAssert (toString(a, 2)).len == nBits | ||
# For bigger bigints, remove the test with slow conversion to string | ||
for nBits in [rand(1..maxBits), 32*rand(1..maxLimbs)]: | ||
for _ in 1 .. 5: | ||
let a: BigInt = initRandomBigInt(nBits, Bits) | ||
doAssert fastLog2(a) == (nBits - 1) | ||
|
||
block: | ||
for nLimbs in [1, 2, 3, 5, 10, 25, 100]: | ||
for _ in 1 .. 5: | ||
let a: BigInt = initRandomBigInt(nLimbs) | ||
let n_bitsA = fastLog2(a) + 1 | ||
doAssert n_bitsA <= 32*nlimbs | ||
doAssert n_bitsA > 32*(nlimbs-1) | ||
|
||
block: # GCD properties but tested on random Bigints | ||
let limitGCD = 100_000 # Special limit for the GCD, otherwise the tests run for hours | ||
let (nBitsA, nBitsB, nBitsC) = (rand(1..limitGCD), rand(1..limitGCD), rand(1..limitGCD)) | ||
let a = initRandomBigInt(nBitsA, Bits) | ||
let b = initRandomBigInt(nBitsB, Bits) | ||
let c = initRandomBigInt(nBitsC, Bits) | ||
doAssert gcd(a, b) == gcd(b, a) | ||
doAssert gcd(a, zero) == a | ||
doAssert gcd(a, a) == a | ||
doAssert gcd(c * a, c * b) == c * gcd(a,b) | ||
doAssert gcd(a, gcd(b, c)) == gcd(gcd(a, b), c) | ||
doAssert gcd(a, b) == gcd(b, a mod b) | ||
|
||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's
unit
supposed to mean here? That doesn't seem to fit at all. Maybemode: RandomMode
?