Page 1 of 1

Splitting Numbers into component parts

Posted: Mon May 02, 2005 11:17 pm
by 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?

Posted: Tue May 03, 2005 5:05 am
by rickyboy
Here's a lame way to do it:

Code: Select all

(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:

Code: Select all

> (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