Splitting Numbers into component parts

For the Compleat Fan
Locked
Jeremy Dunn
Posts: 95
Joined: Wed Oct 13, 2004 8:02 pm
Location: Bellingham WA

Splitting Numbers into component parts

Post 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?

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Post 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
(λx. x x) (λx. x x)

Locked