changing floating point number input.. (was realroots...)



oops. I didn't define tomaxrat.  Fortunately it is already defined with
another name, cl-rat-to-maxima..
so the function is more self contained as show below.  

To summarize:

On input, any floating point format can be used.  If the floating point
value can be sensibly treated as a machine double float, it is made into a
machine double float. If it cannot, it is made into a bigfloat.  The
judgment is:  not too big a (pos or neg) exponent. not too small a (pos or
neg) exponent. not too many digits (more than 16 decimals).

Effects: if you put too many digits in a number like
1.234567890123456789012345e0, then you will get a bigfloat.  If your program
doesn't work with bigfloats, this might be a problem.
if you put too large an exponent, e.g.  1.234e600,  instead of getting an
error, you get a bigfloat.

RJF


;; new version by rjf, aug 26 2006

(defun make-number (indata)
  ;; check first for easy case
  (if (null(cdr indata))		; just an integer
      (return-from make-number (readlist (car indata))))
    
  (let* ((data (nreverse indata))
	 (left (nth 0 data))
	 (point (nth 1 data))
	 (right (nth 2 data))
	 (exponent-marker (car (nth 3 data)))
	 (exponent-sign (nth 4 data))
	 (exponent-value(nth 5 data)))
    ;; say the number is 123.45e6
    (setf left (if (null left) 0 (readlist left)))  ;; convert (#\1 #\2 #\3)
to 123
    (setf right (if (null right)0 (readlist right)));; convert (#\4 #\5) to
45
    (setf exponent-sign (cond ((null exponent-sign) 1) ;; either -1 or 1 for
exponent sign
			      ((char= (car exponent-sign) #\-) -1)
			      (t 1)))
    (setf exponent-value (if (null exponent-value)0 (readlist
exponent-value))); convert exponent 
    ;;Maxima was set up to read in any number as a
    ;; double-float.  though commercial macsyma distinguishes between
    ;; single and double.  In this program we compute the exact
    ;; rational value of a decimal number which is entered in a
    ;; floating point format.  We ask later if the original exponent
    ;; marker, E, D, S, e, d should be believed. That is, can the
    ;; number be represented accurately as a double. If not, we
    ;; convert it to a bigfloat. We may bump up fpprec, the number of
    ;; binary bits needed to convert the number correctly, if
    ;; necessary. (3.32 is bits per decimal digit..)
    
    (let* ((fpprec (max fpprec (round(+ (* 3.32 (+(length (nth 0
data))(length (nth 2 data))))
	 			  (abs exponent-value)))))
	   (therational
	    (* (+ left
		  (if (= right 0) 0
		    (* right
		       (expt 10. (- (length (third data)))))))
	       (if (= exponent-value 0) 1
		 (expt 10. (* exponent-value exponent-sign)))))
	 )
      ;; at this point we can check the exponent marker and see what makes
sense.
      (case exponent-marker
	(#\B  ($bfloat (cl-rat-to-maxima therational))) ;it was a bigfloat
marker. do it.
	(t ;; (#\E #\D #\e #\d nil) one of the others.
	 ;; now check that the number fits within double range.
	 ;; and that the reader presented no more than 16 decimal digits.
	 ;; and that it is not going to underflow to 0.
	 (if (and (< -2 (/ therational #.(expt 2 1023)) 2)
		  (>= 16 (+ (length (nth 0 data))(length (nth 2 data)) ))
		  (not (< -1 (* therational #.(expt 2 1023)) 1)) )
	     
	     (* 1.0d0 therational) ; convert to double.
	   ($bfloat (cl-rat-to-maxima therational)))))))) ;; otherwise, use
bigfloat.