Splitting Numbers into component parts

Started by Jeremy Dunn, May 02, 2005, 04:17:15 PM

Previous topic - Next topic

Jeremy Dunn

I would like to write a function NumberParts that takes an integer or real and returns it as a list with the list of digits composing the number in a list along with the exponent i.e. the number of places that one must move the decimal point left or right. Some examples:



123 -> ((1 2 3) 3)

-12 -> ((-1 -2) 2)

0.12 -> ((1 2) 0)

0.00045 -> ((4 5) -3)



One notes that negative numbers have negative digits in the digit list. My question is what is the best way to do this to get the full precision of both integers and reals? It is trivial to convert such a list into a number but I am not certain of the best way to do the reverse. Any suggestions?

rickyboy

#1
Here's a lame way to do it:
(define (re-remove re str) (replace re str "" 0))

(define (split-number-at-point n)
  (let ((n-split (parse (format "%f" (float n)) "."))
        (sign (if (< n 0) -1 1)))
    (list sign
          (re-remove "^0+" (re-remove "^-" (n-split 0)))
          (re-remove "0+$" (n-split 1)))))

(define (extract-digits str) (map int (explode str)))

(define (number->parts n)
  (letn ((s (split-number-at-point n))
         (sign (s 0))
         (r_0 (extract-digits (s 1)))
         (l_0 (s 2))
         (l (extract-digits (if (empty? r_0)
                                (re-remove "^0+" l_0)
                              l_0)))
         (r (if (and (empty? l_0) (empty? r_0)) '(0) r_0)))
    (list sign
          (append r l)
          (+ (length r)
             (- (length l) (length l_0))))))


Usage and output:
> (number->parts 0.00045)
(1 (4 5) -3)
> (number->parts -0.00045)
(-1 (4 5) -3)
> (number->parts 42.00045)
(1 (4 2 0 0 0 4 5) 2)
> (number->parts 123)
(1 (1 2 3) 3)
> (number->parts -12)
(-1 (1 2) 2)
> (number->parts 0.12)
(1 (1 2) 0)
> (number->parts -0.12)
(-1 (1 2) 0)

> (number->parts 0)
(1 (0) 1)
> (number->parts -0)
(1 (0) 1)
> 0
0
> -0
0

So you can see that I recommend you put your sign somewhere in the list (I have it in position 1), rather than signing every component in the digit list.  Also notice that '0' and '-0' are handled in a way that corresponds to how the newLISP REPL does.



Someone better at this will give you a better answer.  Maybe the lame code given by me will spur them on to give you something better.  :-)



--Rick
(λx. x x) (λx. x x)