如何在 Lisp 中格式化 REPL 输出的数字精度?

Posted

技术标签:

【中文标题】如何在 Lisp 中格式化 REPL 输出的数字精度?【英文标题】:How do I format the digit precision of my REPL output in Lisp? 【发布时间】:2015-12-15 22:58:40 【问题描述】:

我的问题是: 如何设置 REPL 打印输出的精度?

作为一个例子,这里有这个简单的函数:

(defun gaussian (rows cols sigma)
  (let ((filter (make-array `(,rows ,cols)))
    (rowOffset (/ (- rows 1) 2.0))
    (colOffset (/ (- cols 1) 2.0)))
    (loop for i from 0 to (- rows 1)
       do (loop for j from 0 to (- cols 1)
           do (setf (aref filter i j)
            (gaussDistVal i j rowOffset ColOffset sigma))))
    filter))

如果我调用(gaussian 5 5 1),我的输出如下:

#2A((0.01831564 0.082085 0.13533528 0.082085 0.01831564)
    (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
    (0.13533528 0.60653067 1.0 0.60653067 0.13533528)
    (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
    (0.01831564 0.082085 0.13533528 0.082085 0.01831564))

而我想得到:

#2A((0.0 0.1 0.1 0.1 0.0)
    (0.0 0.4 0.6 0.4 0.1)
    (0.1 0.6 1.0 0.6 0.1)
    (0.0 0.4 0.6 0.4 0.1)
    (0.0 0.1 0.1 0.1 0.0))

如果您有答案,能否请您告诉我这些“REPL 自定义”记录在哪里?

(SBCL 1.2.11;Emacs 25 上的 Slime)

【问题讨论】:

旁注:您的loops 可能更好地表达为dotimes:(dotimes (i rows) (dotimes (j cols) #| .... |#) 你可以使用(loop for i from 0 below rows...from 0 是可选的)而不是(loop for i from 0 to (- rows 1)... 或(如果你绝对想在你的范围内做算术)(1- rows) 【参考方案1】:

使用 Common Lisp 漂亮的打印机

Common Lisp 有一个广泛的pretty printer。一个很少使用的功能是用于控制特定类型对象的打印的调度表。请参阅set-pprint-dispatch 如何配置此功能。

函数format具有输出各种形式的浮点数的功能。

这个例子结合了两者:

CL-USER 32 > (set-pprint-dispatch 'float
                                  #'(lambda (s obj)
                                      (format s "~,1F" obj)))
NIL

CL-USER 33 > (setf *print-pretty* t)
T

CL-USER 34 > #2A((0.01831564 0.082085 0.13533528 0.082085 0.01831564)
                 (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
                 (0.13533528 0.60653067 1.0 0.60653067 0.13533528)
                 (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
                 (0.01831564 0.082085 0.13533528 0.082085 0.01831564))

#2A((0.0 0.1 0.1 0.1 0.0)
    (0.1 0.4 0.6 0.4 0.1)
    (0.1 0.6 1.0 0.6 0.1)
    (0.1 0.4 0.6 0.4 0.1)
    (0.0 0.1 0.1 0.1 0.0))

可能还想暂时使用它:

CL-USER 37 > (let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
               (set-pprint-dispatch 'float
                                    #'(lambda (s obj)
                                        (format s "~,1F" obj)))
               (pprint #2A((0.01831564 0.082085 0.13533528 0.082085 0.01831564)
                           (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
                           (0.13533528 0.60653067 1.0 0.60653067 0.13533528)
                           (0.082085 0.36787945 0.60653067 0.36787945 0.082085)
                           (0.01831564 0.082085 0.13533528 0.082085 0.01831564))))

#2A((0.0 0.1 0.1 0.1 0.0)
    (0.1 0.4 0.6 0.4 0.1)
    (0.1 0.6 1.0 0.6 0.1)
    (0.1 0.4 0.6 0.4 0.1)
    (0.0 0.1 0.1 0.1 0.0))

【讨论】:

以上是关于如何在 Lisp 中格式化 REPL 输出的数字精度?的主要内容,如果未能解决你的问题,请参考以下文章

用于 Emacs Lisp 的 REPL

如何在 Common Lisp 中增加或减少数字?

SLIME 交互式开发 - 将代码粘贴到 SLIME REPL 中!= eval 来自缓冲区的命令

为啥 Common Lisp 在没有引号的情况下评估符号本身?

cad lisp脚本 修改

如何使用正则表达式将数字格式化为货币