LISP - digits after decimal point

為{幸葍}努か 提交于 2019-12-06 02:06:33

问题


does anyone know how to specify the numer of digits after the decimal point for a float in Lisp?

Say if I print this command at the REPL:

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

I get:

0.142857150000000 

But the number is rounded at the 8th digit after the decimal point, I need to see a lot of digits after the decimal point in order to see if the number is cyclic and to calculate the period. (Actually I'm starting to try and solve Project Euler's problem 26).

I need to get something like this:

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

Thank you,

Luca


回答1:


Common Lisp does not have floats with arbitrary exactness in its standard.

Common Lisp defines four float types in the standard: SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT, LONG-FLOAT.

You can coerce a ratio to a float using the function COERCE (example in LispWorks):

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

or as a LONG-FLOAT in CLISP

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

To compute with longer float numbers you need extensions to Common Lisp. GNU CLISP has a non-portable extension and can set the number of (binary) digits:

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

Example:

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



回答2:


In addition to Rainer's excellent answer, I think you want to check out the function RATIONALIZE:

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



回答3:


You can also do division by hand, where you would still need values longer then long long long (which is known to be too long for some compilers ;) Something like this:

(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

There might be more efficient ways to calculate the fractional part, but they are too complex (for me, and would be for this example).



来源:https://stackoverflow.com/questions/11984746/lisp-digits-after-decimal-point

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!