【问题标题】:LISP - digits after decimal pointLISP - 小数点后的数字
【发布时间】:2012-08-12 15:50:12
【问题描述】:

有谁知道如何在 Lisp 中为浮点数指定小数点后的位数?

如果我在 REPL 上打印这个命令:

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

我明白了:

0.142857150000000 

但是数字在小数点后第8位四舍五入,我需要查看小数点后的很多位,以查看数字是否循环并计算周期。 (实际上我开始尝试解决 Project Euler 的问题 26)。

我需要这样的东西:

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

谢谢你,

卢卡

【问题讨论】:

    标签: lisp common-lisp number-formatting


    【解决方案1】:

    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
    

    【讨论】:

    • 谢谢,这真的很有帮助。
    【解决方案2】:

    您也可以手动进行除法,您仍然需要比 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
    

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

    【讨论】:

      【解决方案3】:

      除了 Rainer 的出色回答, 我想你想看看函数RATIONALIZE

      (rationalize (float 1/7))
      1/7
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-24
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        • 2017-08-31
        相关资源
        最近更新 更多