Skip to content

Commit

Permalink
Reduce gas usage of pow by about 15 percent. (#7013)
Browse files Browse the repository at this point in the history
  • Loading branch information
orizi authored Jan 7, 2025
1 parent 76e5306 commit cf06407
Showing 1 changed file with 32 additions and 6 deletions.
38 changes: 32 additions & 6 deletions corelib/src/num/traits/ops/pow.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,42 @@ mod mul_based {
type Output = T;

const fn pow(self: T, exp: usize) -> T {
let (tail_exp, head_exp) = DivRem::div_rem(exp, 2);
let tail_result = if tail_exp == 0 {
if exp == 0 {
H::one()
} else {
Self::pow(H::mul(self, self), tail_exp)
};
pow_non_zero_exp(self, exp)
}
}
}

/// Equivalent of `PowByMul::pow` but assumes `exp` is non zero.
const fn pow_non_zero_exp<T, impl H: ConstPowHelper<T>, +Copy<T>, +Drop<T>>(
base: T, exp: usize,
) -> T {
let (tail_exp, head_exp) = DivRem::div_rem(exp, 2);
if head_exp == 0 {
pow_non_zero_exp(H::mul(base, base), tail_exp)
} else {
pow_given_sqrt_base(base, tail_exp, base)
}
}

/// Returns `(sqrt_base * sqrt_base).pow(exp) * acc`.
///
/// Receives the square root of the base to avoid overflow if the squaring is not required for
/// the calculation (mostly when `exp` is 0).
const fn pow_given_sqrt_base<T, impl H: ConstPowHelper<T>, +Copy<T>, +Drop<T>>(
sqrt_base: T, exp: usize, acc: T,
) -> T {
if exp == 0 {
acc
} else {
let (tail_exp, head_exp) = DivRem::div_rem(exp, 2);
let base = H::mul(sqrt_base, sqrt_base);
if head_exp == 0 {
tail_result
H::mul(pow_non_zero_exp(H::mul(base, base), tail_exp), acc)
} else {
H::mul(tail_result, self)
pow_given_sqrt_base(base, tail_exp, H::mul(base, acc))
}
}
}
Expand Down

0 comments on commit cf06407

Please sign in to comment.