2022-06-23 15:33:55 -07:00
|
|
|
/// Recursive implementation of exp.
|
|
|
|
|
/// Equivalent to:
|
|
|
|
|
/// def exp(x, e):
|
|
|
|
|
/// if e == 0:
|
|
|
|
|
/// # The path where JUMPI does not jump to `step_case`
|
|
|
|
|
/// return 1
|
|
|
|
|
/// else:
|
|
|
|
|
/// # This is under the `step_case` label
|
|
|
|
|
/// return (x if e % 2 else 1) * exp(x * x, e // 2)
|
|
|
|
|
/// Note that this correctly handles exp(0, 0) == 1.
|
|
|
|
|
|
|
|
|
|
global exp:
|
|
|
|
|
// stack: x, e, retdest
|
|
|
|
|
dup2
|
|
|
|
|
// stack: e, x, e, retdest
|
|
|
|
|
push step_case
|
|
|
|
|
// stack: step_case, e, x, e, retdest
|
|
|
|
|
jumpi
|
|
|
|
|
// stack: x, e, retdest
|
|
|
|
|
pop
|
|
|
|
|
// stack: e, retdest
|
|
|
|
|
pop
|
|
|
|
|
// stack: retdest
|
|
|
|
|
push 1
|
|
|
|
|
// stack: 1, retdest
|
|
|
|
|
swap1
|
|
|
|
|
// stack: retdest, 1
|
|
|
|
|
jump
|
|
|
|
|
|
|
|
|
|
step_case:
|
|
|
|
|
// stack: x, e, retdest
|
|
|
|
|
push recursion_return
|
|
|
|
|
// stack: recursion_return, x, e, retdest
|
|
|
|
|
push 2
|
|
|
|
|
// stack: 2, recursion_return, x, e, retdest
|
|
|
|
|
dup4
|
|
|
|
|
// stack: e, 2, recursion_return, x, e, retdest
|
|
|
|
|
div
|
|
|
|
|
// stack: e / 2, recursion_return, x, e, retdest
|
|
|
|
|
dup3
|
|
|
|
|
// stack: x, e / 2, recursion_return, x, e, retdest
|
2022-06-25 23:10:08 -07:00
|
|
|
%square
|
2022-06-23 15:33:55 -07:00
|
|
|
// stack: x * x, e / 2, recursion_return, x, e, retdest
|
|
|
|
|
push exp
|
|
|
|
|
// stack: exp, x * x, e / 2, recursion_return, x, e, retdest
|
|
|
|
|
jump
|
|
|
|
|
recursion_return:
|
|
|
|
|
// stack: exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
push 2
|
|
|
|
|
// stack: 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
dup4
|
|
|
|
|
// stack: e, 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
mod
|
|
|
|
|
// stack: e % 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
push 1
|
|
|
|
|
// stack: 1, e % 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
dup4
|
|
|
|
|
// stack: x, 1, e % 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
sub
|
|
|
|
|
// stack: x - 1, e % 2, exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
mul
|
|
|
|
|
// stack: (x - 1) * (e % 2), exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
push 1
|
|
|
|
|
// stack: 1, (x - 1) * (e % 2), exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
add
|
|
|
|
|
// stack: 1 + (x - 1) * (e % 2), exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
mul
|
|
|
|
|
// stack: (1 + (x - 1) * (e % 2)) * exp(x * x, e / 2), x, e, retdest
|
|
|
|
|
swap3
|
|
|
|
|
// stack: retdest, x, e, (1 + (x - 1) * (e % 2)) * exp(x * x, e / 2)
|
|
|
|
|
swap2
|
|
|
|
|
// stack: e, x, retdest, (1 + (x - 1) * (e % 2)) * exp(x * x, e / 2)
|
|
|
|
|
pop
|
|
|
|
|
// stack: x, retdest, (1 + (x - 1) * (e % 2)) * exp(x * x, e / 2)
|
|
|
|
|
pop
|
|
|
|
|
// stack: retdest, (1 + (x - 1) * (e % 2)) * exp(x * x, e / 2)
|
|
|
|
|
jump
|