如何在lisp中以指定格式将数字打印为浮点数?
Posted
技术标签:
【中文标题】如何在lisp中以指定格式将数字打印为浮点数?【英文标题】:How to print numbers as floats with a specified format in lisp? 【发布时间】:2016-11-23 18:52:43 【问题描述】:任意数字可以很容易地转换为带有一些小数的浮点数。例如,使用(format nil "~,2f" 6)
会得到"6.00"
。但是有没有办法使用类似的浮点类型规范直接强制任意数字?即,输出一个数字,而不是一个字符串?或者,我试过(read-from-string (format nil "~,2f" 6))
,但这不保留格式。
我想打印一个包含数字(以及其他 lisp 对象)的嵌套树,作为带有两位小数的浮点数。例如,无论 X 中表示的具体数字类型如何,打印输出可能看起来像 X -> (A 3.00 (7.10 B) (C 8.12) 0.75)
。set-pprint-dispatch 用于这种输出还是格式足够?
【问题讨论】:
我认为您将数字与其印刷表示混淆了。 您的意思是要将整数强制转换为浮点数吗?如(float 6)
=> 6.0
? “保留格式”是什么意思?内存中的数字不包含任何格式。您可以在打印时以您想要的方式格式化任何数字。
@sds 是的,现在我知道你是对的。我真正想做的是打印一个不带引号的数字。我应该只使用 (format t "~,2f" 6) 而不是 (format nil "~,2f" 6)。感谢您的澄清。
@davypough,我建议编辑你的问题,明确表明你期待6.00
,但你得到的是"6.00"
——然后,如果你觉得你现在明白(format t...
很舒服正在打印 6.00
,而(format nil ...
正在返回字符串 "6.00"
,请继续写下答案并接受它,以供未来用户使用。
【参考方案1】:
set-pprint-dispatch 用于这种输出还是格式足够?
让我们试试SET-PPRINT-DISPATCH
:
CL-USER> (let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
(set-pprint-dispatch 'float (lambda (s f) (format s "~,2f" f)))
(write '(A 3.00 (7.10 B) (C 8.12) 0.75) :pretty t))
(A 3.00 (7.10 B) (C 8.12) 0.75) ;; standard output
(A 3.0 (7.1 B) (C 8.12) 0.75) ;; result printed by the REPL
由于漂亮打印调度表是在修改之前复制的,因此与浮点数关联的函数只能从 let-binding 内部调用。当WRITE
的返回值打印到 REPL 时,使用默认的调度表。您可以定义一个全局变量以避免每次需要时重新计算修改后的表。
请注意,如果您没有为:pretty
指定值,那么特殊的*PRINT-PRETTY*
变量将定义是否使用漂亮打印机。详情见22.2.1.4 Pretty Print Dispatch Tables。
我想打印一个包含数字的嵌套树
如果您想要将 任何数字 输出为浮点数,只需在 REAL
类型上调度(不能按您的需要打印具有非零虚部的复数,所以我不建议在number
上调度)。任何必要的强制都会隐式发生:
(let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
(set-pprint-dispatch 'real (lambda (s f) (format s "~,2f" f)))
(write '(A 3 (7.1d0 B) (C 203/25) #C(3/4 0)) :pretty t))
... 写道:
(A 3.00 (7.10 B) (C 8.12) 0.75)
【讨论】:
此应用程序是摘要打印输出,因此效果很好。我在write
之前和之后添加了in-package
语句,以禁止打印非实数的包前缀;并将write
语句嵌入循环中,以在单独的行上打印输入树顶层中的每个项目。 (如果这些变化没有实际意义,请进一步评论。感谢您帮助整理我的想法。)
不客气,谢谢。您可以在本地绑定*package*
而不是使用in-package
,这更简单,因为您不必显式恢复到以前的包,这可能容易出错。但我宁愿在 write 调用中将:escape
设置为 NIL 以避免打印包。见clhs.lisp.se/Body/v_pr_esc.htm#STprint-escapeST。您还可以为符号定义自定义漂亮的打印机功能,例如数字。【参考方案2】:
要强制数字为浮点数,请使用coerce
或float
:
CL-USER 121 > (float 2/3 1.0s0)
0.6666667
CL-USER 122 > (float 2/3 1.0d0)
0.6666666666666666D0
CL-USER 123 > (coerce 2/3 'double-float)
0.6666666666666666D0
请注意,浮点数的精度有限 - 像往常一样。
【讨论】:
以上是关于如何在lisp中以指定格式将数字打印为浮点数?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 x86(32 位)程序集中将无符号整数转换为浮点数?