Skip to content

Commit 88dfbd9

Browse files
authored
Add fastLog2 operation, closes #67 (#71)
1 parent 13c3c33 commit 88dfbd9

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

src/bigints.nim

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,14 @@ iterator `..<`*(a, b: BigInt): BigInt =
10681068
yield res
10691069
inc res
10701070

1071+
func fastLog2*(a: BigInt): int =
1072+
## Computes the logarithm in base 2 of `a`.
1073+
## If `a` is negative, returns the logarithm of `abs(a)`.
1074+
## If `a` is zero, returns -1.
1075+
if a.isZero:
1076+
return -1
1077+
bitops.fastLog2(a.limbs[^1]) + 32*(a.limbs.high)
1078+
10711079
func invmod*(a, modulus: BigInt): BigInt =
10721080
## Compute the modular inverse of `a` modulo `modulus`.
10731081
## The return value is always in the range `[1, modulus-1]`
@@ -1127,3 +1135,4 @@ func powmod*(base, exponent, modulus: BigInt): BigInt =
11271135
result = (result * basePow) mod modulus
11281136
basePow = (basePow * basePow) mod modulus
11291137
exponent = exponent shr 1
1138+

tests/tbigints.nim

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,56 @@ proc main() =
385385
doAssert "fedcba9876543210".initBigInt(base = 16) == b
386386
doAssert "ftn5qj1r58cgg".initBigInt(base = 32) == b
387387

388+
block: # fastLog2
389+
let a = one shl 31
390+
let b = a shl 1
391+
let c = initBigInt(0xfedcba9876543210'u64)
392+
let d = initBigInt("ffffffffffffffffff", base = 16)
393+
394+
# first numbers
395+
doAssert fastLog2(2.initBigInt) == 1
396+
doAssert fastLog2(3.initBigInt) == 1
397+
doAssert fastLog2(4.initBigInt) == 2
398+
doAssert fastLog2(5.initBigInt) == 2
399+
doAssert fastLog2(7.initBigInt) == 2
400+
doAssert fastLog2(8.initBigInt) == 3
401+
doAssert fastLog2(24.initBigInt) == 4
402+
doAssert fastLog2(32.initBigInt) == 5
403+
doAssert fastLog2(48.initBigInt) == 5
404+
405+
# one limb
406+
doAssert fastLog2(a) == 31
407+
408+
# two limbs and more
409+
doAssert fastLog2(b) == 32
410+
doAssert fastLog2(b+a) == 32
411+
doAssert fastLog2(c+b+a) == 63
412+
413+
doAssert fastLog2(d) == 71
414+
doAssert fastLog2(d + one) == 72
415+
doAssert fastLog2(d - one) == 71
416+
doAssert fastLog2(-d) == 71
417+
doAssert fastLog2(-d - one) == 72
418+
doAssert fastLog2(-d + one) == 71
419+
420+
# negative BigInts
421+
doAssert fastLog2(-2.initBigInt) == 1
422+
doAssert fastLog2(-3.initBigInt) == 1
423+
doAssert fastLog2(-4.initBigInt) == 2
424+
doAssert fastLog2(-5.initBigInt) == 2
425+
doAssert fastLog2(-7.initBigInt) == 2
426+
doAssert fastLog2(-8.initBigInt) == 3
427+
doAssert fastLog2(-24.initBigInt) == 4
428+
doAssert fastLog2(-32.initBigInt) == 5
429+
doAssert fastLog2(-48.initBigInt) == 5
430+
doAssert fastLog2(-a) == 31
431+
doAssert fastLog2(-b) == 32
432+
433+
# edge cases
434+
doAssert fastLog2(one) == 0
435+
doAssert fastLog2(zero) == -1
436+
437+
388438
block: # pow
389439
let a = "14075287".initBigInt
390440
doAssert pow(a, 0) == one

0 commit comments

Comments
 (0)