2012-08-16 5 views
5

qualcuno sa come specificare il numero di cifre dopo il punto decimale per un float in Lisp?LISP - cifre dopo il punto decimale

Dire se stampo questo comando al REPL:

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

ottengo:

0.142857150000000 

Ma il numero è arrotondato al 8 cifre dopo la virgola, ho bisogno di vedere un molte cifre dopo il punto decimale per vedere se il numero è ciclico e per calcolare il periodo. (In realtà sto iniziando a provare a risolvere il problema di Project Euler 26).

ho bisogno di ottenere qualcosa di simile:

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

Grazie,

Luca

risposta

17

Common Lisp non hai carri con precisione arbitraria nel suo standard.

Common Lisp definisce quattro tipi di float nello standard: SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT, LONG-FLOAT.

È possibile costringere un rapporto ad un galleggiante mediante la funzione COERCE (ad esempio in LispWorks):

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

o come LONG-FLOAT in CLISP

Per calcolare con numeri float è più necessario estensioni a Common Lisp. GNU CLISP ha un'estensione non portabile e può impostare il numero di cifre (binarie):

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

Esempio:

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

Grazie, è stato davvero utile. – Luca

3

Oltre alla risposta eccellente di Rainer, penso che si desidera controllare la funzione RATIONALIZE:

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

si può anche fare la divisione a mano, in cui si farebbe st valori devono malati più quindi molto molto molto (che è noto per essere troppo lungo per alcuni compilatori;) Qualcosa di simile a questo:

(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 

Ci potrebbero essere modi più efficienti per calcolare la parte frazionaria, ma sono troppo complessi (per me, e sarebbe per questo esempio).