From 3d49038072ce9fe88ac61cb89f5bce65fef8d26f Mon Sep 17 00:00:00 2001 From: Filip Krawczyk Date: Tue, 24 Oct 2023 17:47:53 +0200 Subject: [PATCH] Add fast_pow function --- src/utils/bitwise.cairo | 6 +++- src/utils/math.cairo | 61 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/utils/bitwise.cairo b/src/utils/bitwise.cairo index 95f2189..ab1f9c8 100644 --- a/src/utils/bitwise.cairo +++ b/src/utils/bitwise.cairo @@ -14,7 +14,11 @@ fn left_shift< impl TMul: Mul, impl TOneable: Oneable, impl TCopy: Copy, - impl TDrop: Drop + impl TDrop: Drop, + impl TDiv: Div, + impl TRem: Rem, + impl TPartialEq: PartialEq, + impl TPartialOrd: PartialOrd >( num: T, shift: T ) -> T { diff --git a/src/utils/math.cairo b/src/utils/math.cairo index fe25aa0..7a844c5 100644 --- a/src/utils/math.cairo +++ b/src/utils/math.cairo @@ -4,7 +4,34 @@ use math::Oneable; // @param base The base of the exponentiation // @param exp The exponent of the exponentiation // @return The exponentiation result + fn pow< + T, + impl Zeroable: Zeroable, + impl TOneable: Oneable, + impl TCopy: Copy, + impl TDrop: Drop, + impl TAdd: Add, + impl TSub: Sub, + impl TMul: Mul, + impl TDiv: Div, + impl TRem: Rem, + impl TPartialEq: PartialEq, + impl TPartialOrd: PartialOrd +>( + mut base: T, mut exp: T +) -> T { + let two = TOneable::one() + TOneable::one(); + let four = two + two; + let sixteen = four * four; + if exp < sixteen { + slow_pow(base, exp) + } else { + fast_pow(base, exp) + } +} + +fn slow_pow< T, impl TZeroable: Zeroable, impl TSub: Sub, @@ -18,6 +45,38 @@ fn pow< if exp.is_zero() { TOneable::one() } else { - base * pow(base, exp - TOneable::one()) + base * slow_pow(base, exp - TOneable::one()) + } +} + +fn fast_pow< + T, + impl Zeroable: Zeroable, + impl TOneable: Oneable, + impl TCopy: Copy, + impl TDrop: Drop, + impl TAdd: Add, + impl TSub: Sub, + impl TMul: Mul, + impl TDiv: Div, + impl TRem: Rem, + impl TPartialEq: PartialEq +>( + mut base: T, mut exp: T +) -> T { + let mut ans = TOneable::one(); + loop { + if exp.is_zero() { + break ans; + } + let two = TOneable::one() + TOneable::one(); + let mm = exp % two; + if mm == TOneable::one() { + ans = ans * base; + exp = exp - TOneable::one(); + } else { + base = base * base; + exp = exp / two; + }; } }