From: David Steuber
Subject: Need help with cplx-num-add function
Date: 
Message-ID: <m2y8qeaa77.fsf@david-steuber.com>
I am still a solid newbie, so please bear with me.

I know that Lisp has a complex type, but that works with floating
point numbers.  I am working on a little project where I want
arbitrary precision so I have opted to represent 'complex' numbers as
conses:

(a . b)

I have written a function for adding them:

;;; cplx-num-add -- (a + bi) + (c + di) => (a + c) + (b + d)i
(defun cplx-num-add (&rest args)
  (let ((x (car args))
        (y (cadr args)))
    (if (not (consp x))
        (cons 0 0)
        (if (not (consp y))
            x
            (cplx-num-add (cons (+ (car x) (car y)) (+ (cdr x) (cdr y))) (cddr args))))))

The biggest problem (besides any naivety of the implementation) is
that it fails on the third argument.  I am trying to emulate the
behavior of the add function like so:

> (cplx-num-add)
(0 . 0)

> (cplx-num-add '(1 . 2))
(1 . 2)

> (cplx-num-add '(1 . 2) '(3 . 4))
(4 . 6)

> (cplx-num-add '(1 . 2) '(3 . 4) '(5 . 6))
FAILS complaining that (5 . 6) is not a number.  The complaint is
also about y in the function.

I do not yet know how to use the symbolic debugger.  I am working
with OpenMCL + SLIME in Carbon Emacs.  I also pasted the function
into SBCL which also failed.  I haven't tried CLISP but I figure I
don't need to at this point.

My first question is why the run time error?  How do I fix that?

Second, what would be a better way to write this function?

TIA

-- 
Those who do not remember the history of Lisp are doomed to repeat it,
badly.

> (dwim x)
NIL

From: Barry Margolin
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <barmar-295B05.23182005032004@comcast.ash.giganews.com>
In article <··············@david-steuber.com>,
 David Steuber <·············@verizon.net> wrote:

> I am still a solid newbie, so please bear with me.
> 
> I know that Lisp has a complex type, but that works with floating
> point numbers.

Common Lisp's complex numbers use either floating point or rational 
components.  The only restriction is that both the real and imaginary 
parts have to be the same type.

As long as you never input any floating points into the computations, 
they'll stay with arbitrary-precision rationals.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Peter Seibel
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <m3smgmfs3u.fsf@javamonkey.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@david-steuber.com>,
>  David Steuber <·············@verizon.net> wrote:
>
>> I am still a solid newbie, so please bear with me.
>> 
>> I know that Lisp has a complex type, but that works with floating
>> point numbers.
>
> Common Lisp's complex numbers use either floating point or rational 
> components.  The only restriction is that both the real and imaginary 
> parts have to be the same type.
>
> As long as you never input any floating points into the computations, 
> they'll stay with arbitrary-precision rationals.

Nor use any irrational functions, e.g.:

  > (sin #c(2 3))
  #c(9.154499 -4.168907)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: David Steuber
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <m2hdx2a3in.fsf@david-steuber.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@david-steuber.com>,
>  David Steuber <·············@verizon.net> wrote:
> 
> > I am still a solid newbie, so please bear with me.
> > 
> > I know that Lisp has a complex type, but that works with floating
> > point numbers.
> 
> Common Lisp's complex numbers use either floating point or rational 
> components.  The only restriction is that both the real and imaginary 
> parts have to be the same type.
> 
> As long as you never input any floating points into the computations, 
> they'll stay with arbitrary-precision rationals.

Oh?

$ sbcl
This is SBCL 0.8.8.10, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (* (/ 3 4) (sqrt -1))

#C(0.0 0.75)
* #C(3/4 1/2)

#C(3/4 1/2)
* (+ #C(3/4 1/2) #C(-2/3 1/13))

#C(1/12 15/26)

Well there you go.  I wonder why I thought differently?  I must have
misread something somewhere.  So now I've wasted a whole bunch of
time trying to write my own add function for complex numbers when I
didn't have to.  And it still isn't perfect.

I'll try and pretend my Lisp skill was improved by the exercise or
something.

-- 
Those who do not remember the history of Lisp are doomed to repeat it,
badly.

> (dwim x)
NIL
From: Kenny Tilton
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <OEf2c.18139$Wo2.15390@twister.nyc.rr.com>
David Steuber wrote:

> So now I've wasted a whole bunch of
> time trying to write my own <arbitrary capability> when I
> didn't have to.  And it still isn't perfect.

welcome to the club.

> 
> I'll try and pretend my Lisp skill was improved by the exercise or
> something.

Yeah, that's what I always tell myself. Don't forget the meta-skill of 
learning that whatever you realistically require while programming is 
probably already somewhere out there in this bloated, obese language. 
Mind you, I have been at this for years and still come across stuff I 
missed. My theory is that CL makes it so easy to toss off this stuff 
that we just toss it off without thinking to check if it is already 
covered. And of course most of us grew up on languages which were little 
more than cosmetic sugar for assembler, so we don't /expect/ it to be 
covered.

I love it when trolls try to beat up Lisp for having a big spec. What 
part of "free lunch" do they not understand?

kenneth

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: David Steuber
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <m27jxxctc3.fsf@david-steuber.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> I love it when trolls try to beat up Lisp for having a big spec. What
> part of "free lunch" do they not understand?

Lisp certainly does a lot of nice things for you.  I hope to know
about as many of them as possible.

As for the big spec, I think that is a Good Thing(tm).  The more
portable my Lisp code is between implimentations without having to be
reduced to an uninteresting subset, the better I will like it.  C may
be very portable, but the standard leaves a lot of things to the
implementation, particularly in the area of int sizes and other
things that are very machine dependent.  C programmers generally
don't notice these things because the are programming on one platform
for one compiler.  You can see how messy things get when you start
using autoconf and automake to deal with all the different flavors of
Unix that are out there.  And then you have Windows and Mac OS X.

As for Java, I don't think anyone can call that a small language when
you include the standard class libraries.  And they most certainly
are a part of the language.

I am doing some head banging with Lisp.  But I went through that with
Fortran, Pascal, C, C++, Perl, Java, and other languages.  I expect a
sophisticated language to take time to master.  I also have a fairly
good feeling about Lisp.  I can see that it has potential as
advocates are always saying of it.  I'm not experiencing much of that
yet.  But I think it will come together.  I can feel my mind slowly
beginning to think more like Lisp and less like C.

I hope that is reflected in my second attempt at the cplx-num-add
function.

-- 
Those who do not remember the history of Lisp are doomed to repeat it,
badly.

> (dwim x)
NIL
From: David Steuber
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <m2n06ua40h.fsf@david-steuber.com>
After some fussing around, I conjured up this incantation:

;;; cplx-num-add -- (a + bi) + (c + di) => (a + c) + (b + d)i
(defun cplx-num-add (&rest args)
  (let ((x (cons 0 0)))
    (mapcar #'(lambda (y)
                (setf (car x) (+ (car x) (car y))
                      (cdr x) (+ (cdr x) (cdr y))))
            args)
    x))

It works a lot better although I can still trip it up by trying to
pass in a list of conses.

-- 
Those who do not remember the history of Lisp are doomed to repeat it,
badly.

> (dwim x)
NIL
From: David Sletten
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <jSh2c.14368$rD5.7066@twister.socal.rr.com>
David Steuber wrote:
> After some fussing around, I conjured up this incantation:
> 
> ;;; cplx-num-add -- (a + bi) + (c + di) => (a + c) + (b + d)i
> (defun cplx-num-add (&rest args)
>   (let ((x (cons 0 0)))
>     (mapcar #'(lambda (y)
>                 (setf (car x) (+ (car x) (car y))
>                       (cdr x) (+ (cdr x) (cdr y))))
>             args)
>     x))
> 
> It works a lot better although I can still trip it up by trying to
> pass in a list of conses.
> 
I was going to suggest something similar. The only improvement is that 
MAPC avoids the CONSing that MAPCAR must do in order to produce a result 
which is simply ignored here:
(defun cmplx-add (&rest l)
         (let ((real 0) 

               (imaginary 0)) 

           (mapc #'(lambda (cons) 

                     (incf real (car cons)) 

                     (incf imaginary (cdr cons))) l) 

           (cons real imaginary)))
From: David Steuber
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <m21xo5ct0e.fsf@david-steuber.com>
David Sletten <·····@slytobias.com> writes:

> I was going to suggest something similar. The only improvement is that
> MAPC avoids the CONSing that MAPCAR must do in order to produce a
> result which is simply ignored here:
> (defun cmplx-add (&rest l)
>          (let ((real 0)              (imaginary 0))          (mapc
>          #'(lambda (cons)                    (incf real (car cons))
>          (incf imaginary (cdr cons))) l)          (cons real
>          imaginary)))

Hmmm.  I did not know about MAPC.  I'll have to check that out.

-- 
Those who do not remember the history of Lisp are doomed to repeat it,
badly.

> (dwim x)
NIL
From: Lars Brinkhoff
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <853c8mnrt5.fsf@junk.nocrew.org>
David Steuber <·············@verizon.net> writes:

> After some fussing around, I conjured up this incantation:
> ;;; cplx-num-add -- (a + bi) + (c + di) => (a + c) + (b + d)i
> (defun cplx-num-add (&rest args)
>   (let ((x (cons 0 0)))
>     (mapcar #'(lambda (y)
>                 (setf (car x) (+ (car x) (car y))
>                       (cdr x) (+ (cdr x) (cdr y))))
>             args)
>     x))

This kind of computation is often easily expressed with REDUCE:

  (defun cadd2 (x y)
    (cons (+ (car x) (car y)) (+ (cdr x) (cdr y))))
              
  (defun cplx-num-add (&rest numbers)
    (reduce #'cadd2 numbers :initial-value (cons 0 0)))

(Unless your compiler is quite good) this does a bit of consing, so
David Sletten's version with MAPC (or similar using DOLIST) could be
more efficient.

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Gareth McCaughan
Subject: Re: Need help with cplx-num-add function
Date: 
Message-ID: <873c8m407s.fsf@g.mccaughan.ntlworld.com>
David Steuber wrote:

> ;;; cplx-num-add -- (a + bi) + (c + di) => (a + c) + (b + d)i
> (defun cplx-num-add (&rest args)
>   (let ((x (car args))
>         (y (cadr args)))
>     (if (not (consp x))
>         (cons 0 0)
>         (if (not (consp y))
>             x
>             (cplx-num-add (cons (+ (car x) (car y)) (+ (cdr x) (cdr y)))
>                           (cddr args))))))

The recursive call to CPLX-NUM-ADD is trying to add a complex number
to a list of complex numbers.

    (defconstant +complex-0+ '(0 . 0))
    
    (defun add-complex-2 (x y)
      (cons (+ (car x) (car y))
            (+ (cdr x) (cdr y))))
    
    (defun add-complex (&rest args)
      (if (null args)
        +complex-0+
        (let ((x1     (first args))
              (others (rest args)))
          (if (null others)
            x1
            (add-complex-2 x1 (apply #'add-complex others))))))

You could replace the innermost IF with its second consequent
clause without impairing correctness, but it would make the code
slower.

Alternatively,

    (defun add-complex (&rest args)
      (let ((x 0) (y 0))
        (loop for (p . q) in args do   ;; could use DOLIST if you prefer
          (incf x p)
          (incf y q)
        (cons x y)))

Best of all, as already noted, is to use good ol' Lisp complex
numbers with rational real and imaginary parts.

-- 
Gareth McCaughan
.sig under construc