LISP - 小数点后的数字

7

请问有人知道如何在Lisp中指定浮点数小数点后的位数吗?

比如说,如果我在REPL中执行以下命令:

CL-USER 3 > (format t "~,15f" (float (/ 1 7)))

我得到:

0.142857150000000 

但是该数字在小数点后的第8位被四舍五入了,为了判断该数字是否为循环数字并计算周期,我需要看到更多的小数位。实际上,我正在尝试解决欧拉计划中的问题26。
我需要得到像这样的东西:
CL-USER 3 > (format t "~,15f" (float (/ 1 7)))
0.142857142857142857142857142857142857.... 

谢谢您,Luca。
3个回答

20

Common Lisp标准中没有支持任意精度的浮点数。

在标准中,Common Lisp定义了四种浮点类型:SHORT-FLOATSINGLE-FLOATDOUBLE-FLOATLONG-FLOAT

您可以使用函数COERCE将比值转换为浮点数(LispWorks示例):

CL-USER 1 > (coerce (/ 1 7) 'double-float)
0.14285714285714285D0

或者在CLISP中作为LONG-FLOAT

[1]> (coerce (/ 1 7) 'long-float)
0.14285714285714285714L0

要进行更长的浮点数计算,您需要对Common Lisp进行扩展。GNU CLISP 有一个非便携式的扩展并可以设置(二进制)数字的数量:

(SETF (EXT:LONG-FLOAT-DIGITS) n)

示例:

[3]> (SETF (EXT:LONG-FLOAT-DIGITS) 1000)    
1000
[4]> (coerce (/ 1 7) 'long-float)
0.142857142857142857142857142857142857142857142857142857
142857142857142857142857142857142857142857142857142857
142857142857142857142857142857142857142857142857142857
142857142857142857142857142857142857142857142857142857
142857142857142857142857142857142857142857142857142857
142857142857142857142857142857142857143L0

3

3

您也可以手动进行除法运算,但是您仍然需要比long long long更长的值(对于某些编译器来说,这已经太长了;)例如:

(defun divide (a b &key (precision 8))
  (let ((fractional 0))
    (multiple-value-bind (whole reminder)
        (floor a b)
      (unless (zerop reminder)
        (dotimes (i precision)
          (setf reminder (* reminder 10))
          (multiple-value-bind (quot rem)
              (floor reminder b)
            (setf fractional (+ (* fractional 10) quot))
            (when (zerop rem) (return))
            (setf reminder rem))))
      (values whole fractional))))

(multiple-value-call #'format t "~d.~d~&" (divide 1 7))
(multiple-value-call #'format t "~d.~d~&" (divide 1 7 :precision 54))

;; 0.14285714
;; 0.142857142857142857142857142857142857142857142857142857

可能有更有效的计算小数部分的方法,但它们太复杂了(对我来说是如此,也适用于这个例子)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接