From 536d6c0220eca431266a098c316fb2a806c1fb8b Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Sun, 10 Jul 2022 21:59:21 +0900 Subject: [PATCH 1/2] Add setBit, clearBit and testBit --- src/bigints.nim | 46 ++++++++++++++++++++++++++ tests/tbigints.nim | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/src/bigints.nim b/src/bigints.nim index 9ef5abb..d11dc62 100644 --- a/src/bigints.nim +++ b/src/bigints.nim @@ -1198,3 +1198,49 @@ func powmod*(base, exponent, modulus: BigInt): BigInt = result = (result * basePow) mod modulus basePow = (basePow * basePow) mod modulus exponent = exponent shr 1 + +func getLimbAndBitPosFromBitPos(bit: Natural): tuple[bit, limb: Natural] {.inline.} = + (bit: Natural(bit and 31), limb: Natural(bit shr 5)) + +func setBit*(a: var BigInt; bit: Natural) = + ## Mutates `a`, with the bit at position `bit` set to 1. + runnableExamples: + var v = 0b0000_0011'bi + v.setBit(5) + doAssert v == 0b0010_0011'bi + + let (b, l) = getLimbAndBitPosFromBitPos(bit) + + if l >= a.limbs.len: + a.limbs.setLen(l + 1) + + a.limbs[l] = a.limbs[l] or (1'u32 shl b) + +func clearBit*(a: var BigInt; bit: Natural) = + ## Mutates `v`, with the bit at position `bit` set to 0. + runnableExamples: + var v = 0b0000_0011'bi + v.clearBit(1) + doAssert v == 0b0000_0001'bi + + let (b, l) = getLimbAndBitPosFromBitPos(bit) + + if l >= a.limbs.len: + return + + a.limbs[l] = a.limbs[l] and not (1'u32 shl b) + normalize(a) + +func testBit*(a: BigInt; bit: Natural): bool = + ## Returns true if the bit in `a` at positions `bit` is set to 1. + runnableExamples: + let v = 0b0000_1111'bi + doAssert v.testBit(0) + doAssert not v.testBit(7) + + let (b, l) = getLimbAndBitPosFromBitPos(bit) + + if l >= a.limbs.len: + false + else: + (a.limbs[l] and (1'u32 shl b)) != 0 diff --git a/tests/tbigints.nim b/tests/tbigints.nim index 3b3a59d..95f6073 100644 --- a/tests/tbigints.nim +++ b/tests/tbigints.nim @@ -786,6 +786,88 @@ proc main() = doAssert pred(a, 3) == initBigInt(4) doAssert succ(a, 3) == initBigInt(10) + block: # setBit/clearBit/clearBit + var a = initBigInt(0) + for i in 0..256: + doAssert not a.testBit(i) + for i in 0..256: + a.setBit(i) + for j in 0..i: + doAssert a.testBit(j) + for j in (i + 1)..256: + doAssert not a.testBit(j) + for i in countDown(256, 0): + doAssert a.testBit(i) + for i in countDown(256, 0): + a.clearBit(i) + for j in 0..(i - 1): + doAssert a.testBit(j) + for j in i..256: + doAssert not a.testBit(j) + for i in countDown(256, 0): + doAssert not a.testBit(i) + for i in 1..256: + a.setBit(i) + doAssert a.testBit(i) + doAssert not a.testBit(i - 1) + doAssert not a.testBit(i + 1) + a.clearBit(i) + doAssert not a.testBit(i) + doAssert not a.testBit(i - 1) + doAssert not a.testBit(i + 1) + doAssert a == initBigInt(0) + + a = initBigInt(0) + a.setBit(0) + doAssert a == initBigInt(1) + doAssert a.testBit(0) + a.setBit(1) + doAssert a == initBigInt(3) + doAssert a.testBit(0) and a.testBit(1) + a.setBit(31) + doAssert a == initBigInt((1 shl 31) + 3) + doAssert a.testBit(0) and a.testBit(1) and a.testBit(31) + a.setBit(30) + doAssert a == initBigInt((1 shl 31) + (1 shl 30) + 3) + doAssert a.testBit(0) and a.testBit(1) and a.testBit(30) and a.testBit(31) + a.clearBit(31) + doAssert a == initBigInt((1 shl 30) + 3) + doAssert a.testBit(0) and a.testBit(1) and a.testBit(30) and (not a.testBit(31)) + a.clearBit(30) + doAssert a == initBigInt(3) + doAssert a.testBit(0) and a.testBit(1) and (not a.testBit(30)) and (not a.testBit(31)) + a.clearBit(1) + doAssert a == initBigInt(1) + doAssert a.testBit(0) and (not a.testBit(1)) and (not a.testBit(30)) and (not a.testBit(31)) + a.clearBit(0) + doAssert a == initBigInt(0) + + a = initBigInt(0) + a.setBit(63) + doAssert a == initBigInt(1'u64 shl 63'u64) + doAssert (not a.testBit(1)) and (not a.testBit(31)) and (not a.testBit(32)) and a.testBit(63) + a.setBit(1) + doAssert a == initBigInt((1'u64 shl 63'u64) + 2) + doAssert a.testBit(1) and (not a.testBit(31)) and (not a.testBit(32)) and a.testBit(63) + a.setBit(32) + doAssert a == initBigInt((1'u64 shl 63'u64) + (1'u64 shl 32'u64) + 2) + doAssert a.testBit(1) and (not a.testBit(31)) and a.testBit(32) and a.testBit(63) + a.setBit(31) + doAssert a == initBigInt((1'u64 shl 63'u64) + (1'u64 shl 32'u64) + (1'u64 shl 31'u64) + 2) + doAssert a.testBit(1) and a.testBit(31) and a.testBit(32) and a.testBit(63) + + a.clearBit(63) + doAssert a == initBigInt((1'u64 shl 32'u64) + (1'u64 shl 31'u64) + 2) + doAssert a.testBit(1) and a.testBit(31) and a.testBit(32) and (not a.testBit(63)) + a.clearBit(1) + doAssert a == initBigInt((1'u64 shl 32'u64) + (1'u64 shl 31'u64)) + doAssert (not a.testBit(1)) and a.testBit(31) and a.testBit(32) and (not a.testBit(63)) + a.clearBit(32) + doAssert a == initBigInt((1'u64 shl 31'u64)) + doAssert (not a.testBit(1)) and a.testBit(31) and (not a.testBit(32)) and (not a.testBit(63)) + a.clearBit(31) + doAssert a == initBigInt(0) + doAssert (not a.testBit(1)) and (not a.testBit(31)) and (not a.testBit(32)) and (not a.testBit(63)) static: main() main() From 31d04476233c0acd7753f25463b13d16c5d6cdd2 Mon Sep 17 00:00:00 2001 From: demotomohiro Date: Wed, 13 Jul 2022 02:52:00 +0900 Subject: [PATCH 2/2] Fix errors on nim-1.4.8 --- src/bigints.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bigints.nim b/src/bigints.nim index d11dc62..41a504d 100644 --- a/src/bigints.nim +++ b/src/bigints.nim @@ -1205,9 +1205,9 @@ func getLimbAndBitPosFromBitPos(bit: Natural): tuple[bit, limb: Natural] {.inlin func setBit*(a: var BigInt; bit: Natural) = ## Mutates `a`, with the bit at position `bit` set to 1. runnableExamples: - var v = 0b0000_0011'bi + var v = 0b0000_0011.initBigInt v.setBit(5) - doAssert v == 0b0010_0011'bi + doAssert v == 0b0010_0011.initBigInt let (b, l) = getLimbAndBitPosFromBitPos(bit) @@ -1219,9 +1219,9 @@ func setBit*(a: var BigInt; bit: Natural) = func clearBit*(a: var BigInt; bit: Natural) = ## Mutates `v`, with the bit at position `bit` set to 0. runnableExamples: - var v = 0b0000_0011'bi + var v = 0b0000_0011.initBigInt v.clearBit(1) - doAssert v == 0b0000_0001'bi + doAssert v == 0b0000_0001.initBigInt let (b, l) = getLimbAndBitPosFromBitPos(bit) @@ -1234,7 +1234,7 @@ func clearBit*(a: var BigInt; bit: Natural) = func testBit*(a: BigInt; bit: Natural): bool = ## Returns true if the bit in `a` at positions `bit` is set to 1. runnableExamples: - let v = 0b0000_1111'bi + let v = 0b0000_1111.initBigInt doAssert v.testBit(0) doAssert not v.testBit(7)