From 1283d582a10a4c9a2879e29e25855fb8bef04f47 Mon Sep 17 00:00:00 2001 From: mratsim Date: Mon, 14 May 2018 19:44:39 +0200 Subject: [PATCH] implement a pow for x, y: UintImpl as well --- stint/private/uint_exp.nim | 21 ++++++++++++++++++++- stint/uint_public.nim | 6 ++++++ tests/property_based.nim | 7 +++++++ tests/test_uint_exp.nim | 5 ++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/stint/private/uint_exp.nim b/stint/private/uint_exp.nim index 166a428..01db358 100644 --- a/stint/private/uint_exp.nim +++ b/stint/private/uint_exp.nim @@ -9,7 +9,7 @@ import ./datatypes, - ./uint_bitwise_ops, ./uint_mul, ./initialization + ./uint_bitwise_ops, ./uint_mul, ./initialization, ./uint_comparison func pow*(x: UintImpl, y: Natural): UintImpl = ## Compute ``x`` to the power of ``y``, @@ -29,3 +29,22 @@ func pow*(x: UintImpl, y: Natural): UintImpl = if y == 0: break x = x * x + +func pow*(x: UintImpl, y: UintImpl): UintImpl = + ## Compute ``x`` to the power of ``y``, + ## ``x`` must be non-negative + + # Implementation uses exponentiation by squaring + # See Nim math module: https://github.com/nim-lang/Nim/blob/4ed24aa3eb78ba4ff55aac3008ec3c2427776e50/lib/pure/math.nim#L429 + # And Eli Bendersky's blog: https://eli.thegreenplace.net/2009/03/21/efficient-integer-exponentiation-algorithms + + var (x, y) = (x, y) + result = one(type x) + + while true: + if not (y and one(type y)).isZero: + result = result * x + y = y shr 1 + if y.isZero: + break + x = x * x diff --git a/stint/uint_public.nim b/stint/uint_public.nim index bda1570..e1fa69b 100644 --- a/stint/uint_public.nim +++ b/stint/uint_public.nim @@ -94,3 +94,9 @@ func pow*(x: StUint, y: Natural): StUint {.inline.} = result.data = x.data.pow(y) else: result.data = x.data ^ y + +func pow*(x: StUint, y: StUint): StUint {.inline.} = + when x.data is UintImpl: + result.data = x.data.pow(y.data) + else: + result.data = x.data ^ y.data diff --git a/tests/property_based.nim b/tests/property_based.nim index be3bdab..68f6f18 100644 --- a/tests/property_based.nim +++ b/tests/property_based.nim @@ -223,9 +223,16 @@ suite "Property-based testing (testing with random inputs) - uint64 on 64-bit / let tx = cast[StUint[64]](x) tz = tx.pow(y) + + ty = cast[StUint[64]](y) + tz2 = tx.pow(ty) else: let tx = cast[StUint[32]](x) tz = tx.pow(y) + ty = cast[StUint[32]](y) + tz2 = tx.pow(ty) + check(cast[uint](tz) == x ^ y) + check(cast[uint](tz2) == x ^ y) diff --git a/tests/test_uint_exp.nim b/tests/test_uint_exp.nim index c862898..05944d6 100644 --- a/tests/test_uint_exp.nim +++ b/tests/test_uint_exp.nim @@ -17,7 +17,9 @@ suite "Testing unsigned exponentiation": b = 3 u = a.stuint(64) - check: cast[uint64](u.pow(b)) == a ^ b + check: + cast[uint64](u.pow(b)) == a ^ b + cast[uint64](u.pow(b.stuint(64))) == a ^ b test "12 ^ 34 == 4922235242952026704037113243122008064": # https://www.wolframalpha.com/input/?i=12+%5E+34 @@ -26,3 +28,4 @@ suite "Testing unsigned exponentiation": b = 34 check: a.pow(b) == "4922235242952026704037113243122008064".u256 + check: a.pow(b.stuint(256)) == "4922235242952026704037113243122008064".u256