schmem语言实现快速幂

使用 Scheme 语言重写的 C++ 快速幂(模幂运算)代码。

//相关C++代码
typedef long long LL;
LL qmi(int a, int b, int p)
{
    LL res = 1 % p;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * (LL)a % p;
        b >>= 1;
    }
    return res;
}

我们将 C++ 中的 while 循环迭代实现,转换为 Scheme 中等价且高效的尾递归实现。

Scheme 代码

这个版本使用一个命名的 let 来创建一个尾递归循环,这与 C++ 中的 while 循环在逻辑上是完全对应的。

(define (qmi a b p)
  ;; 使用一个命名的 let 'loop' 来进行尾递归,模拟 C++ 的 while 循环
  ;; a: 当前的底数 (C++ 中的 a)
  ;; b: 当前的指数 (C++ 中的 b)
  ;; res: 累积的结果 (C++ 中的 res)
  (let loop ((a (remainder a p)) ; 初始 a 对 p 取模
             (b b)
             (res 1))
    ;; 当指数 b 为 0 时,循环结束,返回结果
    (if (= b 0)
        res
        ;; 否则,继续下一次递归
        (loop
          ;; 更新 a: a = a * a % p
          (remainder (* a a) p)
          ;; 更新 b: b = b / 2 (整数除法)
          (quotient b 2)
          ;; 更新 res: 如果 b 是奇数, res = res * a % p
          (if (odd? b)
              (remainder (* res a) p)
              res)))))

代码解释

  1. 函数定义:
    define (qmi a b p) 定义了一个名为 qmi 的函数,接受三个参数:底数 a、指数 b 和模数 p

  2. 尾递归循环:

    • let loop (...) 在 Scheme 中创建了一个局部作用域的循环。通过在循环内部调用 loop 本身,我们实现了递归。因为这个调用是函数的最后一个操作,所以它是“尾递归”,Scheme 解释器会将其优化为迭代,避免了堆栈溢出的风险,效率与 C++ 的 while 循环相当。
    • loop 有三个状态变量,完全对应 C++ 版本中的变量:
      • a: 对应 C++ 中的 a,在每次迭代中都会被平方。初始值是 (remainder a p)
      • b: 对应 C++ 中的 b,在每次迭代中都会被右移一位(即整除2)。
      • res: 对应 C++ 中的 res,用于累积结果。初始值为 1。
  3. 循环终止条件:

    • (if (= b 0) res ...) 检查指数 b 是否为 0。如果是,说明计算完成,返回累积的结果 res。这相当于 C++ 中的 while (b) 的循环终止条件。
  4. 循环体逻辑:

    • loop 的三个新参数对应着 C++ 循环体中变量的更新。
    • 更新 a: (remainder (* a a) p) 对应 C++ 的 a = a * (LL)a % p;
    • 更新 b: (quotient b 2) 对应 C++ 的 b >>= 1; (quotient 是整数除法)。
    • 更新 res: (if (odd? b) (remainder (* res a) p) res) 对应 C++ 的 if (b & 1) res = res * a % p; (odd? b) 用于检查 b 的最低位是否为1。

与 C++ 代码的对比

C++ 版本 (while 循环) Scheme 版本 (尾递归 loop) 说明
LL res = 1 % p; (res 1) 初始化结果 res 为 1。
while (b) (if (= b 0) res ...) 循环条件:当 b 不为 0 时继续。
if (b & 1) (if (odd? b) ...) 检查 b 是否为奇数。
res = res * a % p; (remainder (* res a) p) 如果 b 是奇数,则更新 res
a = a * (LL)a % p; (remainder (* a a) p) a 自我平方并取模,为下一次迭代做准备。
b >>= 1; (quotient b 2) b 右移一位(整除2)。
类型处理 (LL) 自动大数处理 C++ 需要 long long 来防止 a*a 溢出,而 Scheme 自动支持大整数运算,无需特殊处理。

如何使用

你可以像这样调用这个函数:

;; 计算 3^5 mod 7
(qmi 3 5 7)
;; => 5

;; 计算 2^100 mod 31
(qmi 2 100 31)
;; => 1
posted @ 2025-08-29 21:37  立体风  阅读(9)  评论(0)    收藏  举报