You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以Common Lisp惯用方式优化进制转换函数避免代码重复?

十进制转任意进制的Common Lisp实现优化

手动计算示例

250 : 8 = 31 + 2
 31 : 8 = 3 + 7
∴ (372)₈

原实现函数

对应的Common Lisp函数如下:

(defun dec->opns (n base)
   (do* ((lst nil (append lst (list pos))) ; this is also not so nice
         (m n (truncate m base))
         (pos (rem m base) (rem m base)) ) ; <<<<<<<<
        ((< m base) (reverse (append lst (list m)))) ))

该函数运行正常,测试示例:

CL-USER> (dec->opns 2500000 8)
(1 1 4 2 2 6 4 0)

优化目标与背景

希望避免代码中重复出现的(rem m base),同时找到更优雅的惯用实现。另外,作为小学教师资格备考者,希望结合Papert《Mindstorms》的思路,从算法实现反思数学教学案例,中期计划开发Common Lisp版Logo环境cλogos(可通过quickload加载)。


优化方案:消除重复计算,提升代码优雅性

Common Lisp的truncate函数会同时返回商和余数两个值,利用这个特性可以一次性获取所需结果,避免重复调用rem。同时,原代码中用append累积列表效率较低,改用push后反转列表是更惯用的写法。

1. 迭代式优化实现(高效且惯用)

(defun dec->opns (n base)
  (do ((lst nil)
       (current n))
      ((< current base) (reverse (cons current lst)))
    (multiple-value-bind (quotient remainder)
        (truncate current base)
      (push remainder lst)
      (setf current quotient))))
  • 用multiple-value-bind一次性绑定商和余数,消除重复计算
  • 用push向列表头部添加余数(O(1)操作,比append高效)
  • 循环结束时将最终的商加入列表,再反转得到正确顺序

2. 递归式实现(贴合手动计算逻辑,适合教学反思)

如果更看重逻辑的直观性,递归实现完全复刻手动“除基取余”的步骤,非常适合用来拆解教学中的算法逻辑:

(defun dec->opns (n base)
  (if (< n base)
      (list n)
      (multiple-value-bind (quotient remainder)
          (truncate n base)
        (append (dec->opns quotient base) (list remainder)))))
  • 当数值小于进制数时,直接返回单元素列表(对应手动计算的最后一步商)
  • 否则计算商和余数,递归处理商后将余数追加到结果末尾,完全对应手动计算的流程

教学视角的延伸思考

从Papert的建构主义教学思路来看:

  • 递归版本的代码逻辑和手动计算步骤完全对齐,每一次递归调用就是一次除法运算,能帮助理解“进制转换”的核心是逐步分解数值,累积余数
  • 迭代版本则展示了“循环累积结果”的思路,适合引导学生理解“重复操作-收集结果-调整顺序”的过程
  • 两种实现都能用来反思:如何把抽象的数学算法拆解成学生能理解的分步操作,比如用Logo的海龟绘图来模拟“除基取余”的过程,让学生直观看到每一步的结果

内容的提问来源于stack exchange,提问作者Demihm Seinname

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:00:24