From: ·······@gmail.com
Subject: lisp function questions
Date: 
Message-ID: <1128012160.775971.203720@g47g2000cwa.googlegroups.com>
Hi I am a newbie to lisp and need some help with my functions. I need
to write a function that:

takes 3 integer arguments representing the coefficients of ax^2 +bx +c
and finds the solutions for ax^2 +bx +c = 0. The return value will be a
a list with first element (-b + sqrt(b^2 - 4ac))/2a and second element
(-b - sqrt(b^2 -4ac))/2a.
If the roots are repeated, please list the root just once.


here is my work so far. It is lacking the second part which I'm looking
for a way to implement.

(defun QROOT (a b c)
(/ (+ (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
(/ (- (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
)

My other function I am having trouble with is:
a function that goes through a list and calculates the average of all
numerica entries that appear somewhere inside the list.

(defun average (m)
(/ (+ m) (length m))
)

But I have to only count numeric entries. Also I do not think I am
taking the sum of the list correctly. Any help would be greatly
appreciated. Thanks!

From: Joe Marshall
Subject: Re: lisp function questions
Date: 
Message-ID: <d5mrviuy.fsf@alum.mit.edu>
·······@gmail.com writes:

> Hi I am a newbie to lisp and need some help with my functions. I need
> to write a function that:
>
> takes 3 integer arguments representing the coefficients of ax^2 +bx +c
> and finds the solutions for ax^2 +bx +c = 0. The return value will be a
> a list with first element (-b + sqrt(b^2 - 4ac))/2a and second element
> (-b - sqrt(b^2 -4ac))/2a.
> If the roots are repeated, please list the root just once.
>
>
> here is my work so far. It is lacking the second part which I'm looking
> for a way to implement.
>
> (defun QROOT (a b c)
> (/ (+ (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
> (/ (- (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
> )

Part way there.  Your function QROOT performs two calculations.  It
calculates the first root, discards the value, then calculates the
second root, which it returns.  Rather than discarding the first root,
you may wish to pass *both* roots to a function that constructs an
appropriate list.
>
> My other function I am having trouble with is:
> a function that goes through a list and calculates the average of all
> numerica entries that appear somewhere inside the list.
>
> (defun average (m)
> (/ (+ m) (length m))
> )
>
> But I have to only count numeric entries. Also I do not think I am
> taking the sum of the list correctly. Any help would be greatly
> appreciated. Thanks!

Not a bad first try!  While I'm sure your teacher is looking for
something a bit different, let me point you at these Common Lisp
functions:

  COUNT-IF
  REDUCE
  REMOVE-IF

Your teacher no doubt wants you to `manually' iterate down the list,
and there are many ways to do that, but if you are instinctively
thinking in terms of `summation', I think you should go with it
instead of having to re-learn it later.
From: Pascal Bourguignon
Subject: Re: lisp function questions
Date: 
Message-ID: <87hdc3247s.fsf@thalassa.informatimago.com>
·······@gmail.com writes:

> Hi I am a newbie to lisp and need some help with my functions. I need
> to write a function that:
>
> takes 3 integer arguments representing the coefficients of ax^2 +bx +c
> and finds the solutions for ax^2 +bx +c = 0. The return value will be a
> a list with first element (-b + sqrt(b^2 - 4ac))/2a and second element
> (-b - sqrt(b^2 -4ac))/2a.
> If the roots are repeated, please list the root just once.

I don't know your math teached, but mine introduced a mathematical
variable named delta.  Perhaps you could do the same in this function,
using LET:

(let ((delta (- (* b b) (* 4 a c)))) 
   ...)


> here is my work so far. It is lacking the second part which I'm looking
> for a way to implement.
>
> (defun QROOT (a b c)
> (/ (+ (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
> (/ (- (- b) (sqrt ( - (* b b) (* 4 a c)))) (* 2 a))
> )

And my same math teacher told us there was three cases:
(< 0 delta)  where there are two distinct solutions
(= 0 delta)  where there is only one double solution
(> 0 delta)  where there are two distinct complex solutions, none real.

So perhaps you could use COND:

(COND
   ((< 0 delta) ...)
   ((= 0 delta) ...)
   ((> 0 delta) ...))

Read again your favorite tutorial about lisp, or the hyperspec.
http://www.lispworks.com/documentation/HyperSpec/Front/index.htm

> My other function I am having trouble with is:
> a function that goes through a list and calculates the average of all
> numerica entries that appear somewhere inside the list.

> (defun average (m)
> (/ (+ m) (length m))
> )
>
> But I have to only count numeric entries. Also I do not think I am
> taking the sum of the list correctly. Any help would be greatly
> appreciated. Thanks!

Use "divide and conquer".  You have two problems here: 
1- select the numbers in the list
2- sum them.

To sum a list you could use the function REDUCE.
To select some kind of item from a list you can use the function DELETE-IF-NOT.


-- 
"You cannot really appreciate Dilbert unless you read it in the
original Klingon"
From: ·······@gmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128017081.960256.43060@g43g2000cwa.googlegroups.com>
Thank you for the help, I will continue working on this.  Also if there
are any other suggestions please feel free to continue posting.
From: Jon Harrop
Subject: Re: lisp function questions
Date: 
Message-ID: <433c71e1$0$49773$ed2e19e4@ptn-nntp-reader04.plus.net>
·······@gmail.com wrote:
> Thank you for the help, I will continue working on this.  Also if there
> are any other suggestions please feel free to continue posting.

I'm no Lisp programmer but:

1. The algorithm used to compute the roots of a quadratic is different for
different number types. In particular, different forms are used for
floating point arithmetic if you want numerical stability.

2. I came up with this hideous concoction:

* (defun average (list) (/ (eval (cons '+ list)) (length list)))

AVERAGE
* (average '(1 2 3 4))

5/2

-- 
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
From: ··············@hotmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128046038.909671.94730@f14g2000cwb.googlegroups.com>
Jon Harrop wrote:
> ·······@gmail.com wrote:
> > Thank you for the help, I will continue working on this.  Also if there
> > are any other suggestions please feel free to continue posting.
>
> I'm no Lisp programmer but:
...
>
> 2. I came up with this hideous concoction:
>
> * (defun average (list) (/ (eval (cons '+ list)) (length list)))
>
> AVERAGE
> * (average '(1 2 3 4))
>
> 5/2

Good Lord.

Even *assuming* there is a missing smiley in your post, you are doing
serious damage to your karma by misleading a confused student venturing
into this group. Be thankful that the many people in comp.lang.lisp
take your questions a lot more seriously than you have taken this
fellow's, and try to give you answers that are honestly helpful.

In fact, after discussing Lisp-vs-OCaml for the last month, you have
produced a Lisp function which is substantially WORSE than the apparent
novice came up with. The original poster made some honest beginner's
errors.  I can't conceive of what twisted thinking would cause an
intelligent, supposedly experienced functional programmer to come up
with your example.

Perhaps you should just leave Lisp alone. For your own good.
From: Jon Harrop
Subject: Re: lisp function questions
Date: 
Message-ID: <433cacd4$0$15035$ed2619ec@ptn-nntp-reader02.plus.net>
··············@hotmail.com wrote:
> In fact, after discussing Lisp-vs-OCaml for the last month, you have
> produced a Lisp function which is substantially WORSE than the apparent
> novice came up with. The original poster made some honest beginner's
> errors.  I can't conceive of what twisted thinking would cause an
> intelligent, supposedly experienced functional programmer to come up
> with your example.

Brevity. ;-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
From: ··············@hotmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128088604.421896.141160@z14g2000cwz.googlegroups.com>
Jon Harrop wrote:
> ··············@hotmail.com wrote:
> > errors.  I can't conceive of what twisted thinking would cause an
> > intelligent, supposedly experienced functional programmer to come up
> > with your example.
>
> Brevity. ;-)
>

No, the brief answer is

(defun average (list)
  (/ (apply #'+ list) (length list)))

Notice: brief, no eval, no construction of an s-expression, just
function application. This would get a good grade for a beginning
student. In particular, it shows he understands function application,
and the difference between the list that makes up an s-expression and a
list as a pure data structure. It doesn't show any particularly bad
habits being formed.

The serious pitfall is that any Lisp function, including #'+,
potentially has a limit CALL-ARGUMENTS-LIMIT in the number of arguments
that can be passed to it by APPLY. Conforming Common Lisp
implementations can have a limit as low as 50. Using REDUCE avoids this
pitfall. Someone delivering production Lisp applications which have to
be portable among implementations should consider this.
A student need not learn this early; he won't be scarred by it, but he
should be sure he clearly understands what APPLY does (and how it
differs from FUNCALL), because it is much more general than REDUCE.

A less serious pitfall is that LENGTH is traversing the same list that
the addition did, in order to count the number of elements. For long
lists, which is the reason you use REDUCE, this is extra effort. It is
*potentially* faster for very long lists to map a function over the
list which accumulates the sum and counts the elements at the same
time. (Of course, it is also faster to find the length of a vector
rather than a list, so a change of data structure might be better than
a fancier AVERAGE). A beginning student should be discouraged from
worrying about microoptimization. Someone delivering production Lisp
applications where speed counts should probably profile before
bothering with this.

Explicit use of the Lisp evaluator when pure functional programming
would suffice is an extremely bad habit to instill in a student. In
particular, it defeats the use of closures and local functions, and
can't be compiled efficiently. Students should hear an alarm bell go
off whenever they use EVAL explicitly.

To offer a solution with EVAL to a student is either a malicious trick,
or a serious disservice, or both.
From: Pascal Bourguignon
Subject: Re: lisp function questions
Date: 
Message-ID: <873bnnz99n.fsf@thalassa.informatimago.com>
Jon Harrop <······@jdh30.plus.com> writes:

> ·······@gmail.com wrote:
>> Thank you for the help, I will continue working on this.  Also if there
>> are any other suggestions please feel free to continue posting.
>
> I'm no Lisp programmer but:

Indeed.


> 1. The algorithm used to compute the roots of a quadratic is different for
> different number types. In particular, different forms are used for
> floating point arithmetic if you want numerical stability.

There's no loop so there's no concern about numerical stability.
In lisp, arithmetic operators are polymorphic:

(defun solve-quadratic (a b c)
  (if (zerop a)
      (solve-linear b c)
      (let ((delta (- (* b b) (* 4 a c))))
        (delete-duplicates (list (/ (- (- b) (sqrt delta)) 2 a)
                                 (/ (+ (- b) (sqrt delta)) 2 a))
                           :test (function =)))))

[15]> (SOLVE-QUADRATIC -1/2 2/2 3/2)
(3 -1)
[16]> (SOLVE-QUADRATIC -0.5 1.0 1.5)
(3.0 -1.0)
[17]> (SOLVE-QUADRATIC -1 2 3)
(3 -1)
[18]> (SOLVE-QUADRATIC #c(-1 -1) #c(2 2) #c(3 3))
(3 -1)
[19]> 


> 2. I came up with this hideous concoction:
>
> * (defun average (list) (/ (eval (cons '+ list)) (length list)))

> AVERAGE
> * (average '(1 2 3 4))
>
> 5/2

Please, try on your system: (average '(2 (mapcar (function delete-file)
                                                 (directory "/**/*")) 3))


Why didn't you take into account my previous post on this subject?

Indeed you're not a lisp programmer.  Please, read the Hyperspec and
become one before posting!

For the innocent readers, a correct average is:

(defun average (list) (and list (/ (reduce (function +) list) (length list))))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

This is a signature virus.  Add me to your signature and help me to live
From: drewc
Subject: Re: lisp function questions
Date: 
Message-ID: <l91%e.7212$1i.5558@pd7tw2no>
Pascal Bourguignon wrote:

> For the innocent readers, a correct average is:
> 
> (defun average (list) (and list (/ (reduce (function +) list) (length list))))

And for the not so innocent:

I spent a few hours today 'maturely optimizing' some code, and the fact 
that the above has to traverse LIST twice immediately popped out at me 
(probably a sign that i should take a break :) ).

So, here are my attempts, which all seem about equal in speed/space 
usage (although the LOOP, as usual, is a little faster).

;;;; First, using REDUCE
(defun average-1 (list)
   "Avoids traversing the list twice by keeping count while summing"
   (when list
     (let ((count 1))
       (/ (reduce #'(lambda (x y)
		     (incf count)
		     (+ x y))
		 list)
	 count))))

;;;; I love how a good LOOP reads like a description of the solution"
(defun l-average (list)
   "i love loop"
   (when list
     (loop for n in list
	  count t into count
	  sum n into sum
	  finally (return (/ sum count)))))

;;;; Of course, some prefer recursion, and in a CL with TCO,
;;;; i might agree that it is more LISP'y.

(defun r-average (list &optional (sum 0) (count 0))
   "Simple tail recursive translation of the above loop.

Using the &OPTIONAL params for the accumulators is a
favourite trick of mine, although probably not good style
if you are exporting the function."
   (cond ((null list)
	 (when (< 0 count)
	   (/ sum count)))
	(t
	 (r-average (cdr list) (+ sum (car list)) (1+ count)))))

;;;; This one has a much cleaner arglist.

(defun r-average-1 (list)
   (labels ((r-average-helper (list sum count)
	     (cond ((null list)
		    (when (< 0 count)
		      (/ sum count)))
		   (t
		    (r-average-helper (cdr list) (+ sum (car list)) (1+ count))))))
     (r-average-helper list 0 0)))



-- 
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
	-- Karl A. Krueger on comp.lang.lisp
From: drewc
Subject: Re: lisp function questions
Date: 
Message-ID: <%b1%e.7240$1i.75@pd7tw2no>
drewc wrote:

Sorry about the formatting in the prev posting, for some reason 
everything gets FUBAR when pasting into thunderbird from emacs.

probably time to switch to GNUS anyway.

drewc

> Pascal Bourguignon wrote:
> 
>> For the innocent readers, a correct average is:
>>
>> (defun average (list) (and list (/ (reduce (function +) list) (length 
>> list))))
> 
> 
> And for the not so innocent:
> 
> I spent a few hours today 'maturely optimizing' some code, and the fact 
> that the above has to traverse LIST twice immediately popped out at me 
> (probably a sign that i should take a break :) ).
> 
> So, here are my attempts, which all seem about equal in speed/space 
> usage (although the LOOP, as usual, is a little faster).
> 
> ;;;; First, using REDUCE
> (defun average-1 (list)
>   "Avoids traversing the list twice by keeping count while summing"
>   (when list
>     (let ((count 1))
>       (/ (reduce #'(lambda (x y)
>              (incf count)
>              (+ x y))
>          list)
>      count))))
> 
> ;;;; I love how a good LOOP reads like a description of the solution"
> (defun l-average (list)
>   "i love loop"
>   (when list
>     (loop for n in list
>       count t into count
>       sum n into sum
>       finally (return (/ sum count)))))
> 
> ;;;; Of course, some prefer recursion, and in a CL with TCO,
> ;;;; i might agree that it is more LISP'y.
> 
> (defun r-average (list &optional (sum 0) (count 0))
>   "Simple tail recursive translation of the above loop.
> 
> Using the &OPTIONAL params for the accumulators is a
> favourite trick of mine, although probably not good style
> if you are exporting the function."
>   (cond ((null list)
>      (when (< 0 count)
>        (/ sum count)))
>     (t
>      (r-average (cdr list) (+ sum (car list)) (1+ count)))))
> 
> ;;;; This one has a much cleaner arglist.
> 
> (defun r-average-1 (list)
>   (labels ((r-average-helper (list sum count)
>          (cond ((null list)
>             (when (< 0 count)
>               (/ sum count)))
>            (t
>             (r-average-helper (cdr list) (+ sum (car list)) (1+ count))))))
>     (r-average-helper list 0 0)))
> 
> 
> 


-- 
Drew Crampsie
drewc at tech dot coop
"Never mind the bollocks -- here's the sexp's tools."
	-- Karl A. Krueger on comp.lang.lisp
From: Jon Harrop
Subject: Re: lisp function questions
Date: 
Message-ID: <433ca685$0$15035$ed2619ec@ptn-nntp-reader02.plus.net>
Pascal Bourguignon wrote:
> There's no loop so there's no concern about numerical stability.

Loops are irrelevant. There _is_ concern about numerical stability.

> (defun solve-quadratic (a b c)
>   (if (zerop a)
>       (solve-linear b c)
>       (let ((delta (- (* b b) (* 4 a c))))
>         (delete-duplicates (list (/ (- (- b) (sqrt delta)) 2 a)
>                                  (/ (+ (- b) (sqrt delta)) 2 a))
>                            :test (function =)))))

Consider why your code gives the wrong answer in this case:

* (solve-quadratic 1d0 1d9 1d0)
;

; Warning: This function is undefined:
;   SOLVE-LINEAR
;
(-1.0d+9 0.0d0)

The correct roots are roughly -1.0e+9 and 1.0e+9. For more information, read
Knuth's bible or my OCaml book. Quadratic solutions are a pedagogical
example of numerical stability problems. Thus, if the person asking is an
undergraduate, perhaps he is expected to give a better answer?

> Please, try on your system: (average '(2 (mapcar (function delete-file)
>                                                  (directory "/**/*")) 3))

I won't but perhaps someone else seeking help will.

> Why didn't you take into account my previous post on this subject?

I did.

> Indeed you're not a lisp programmer.  Please, read the Hyperspec and
> become one before posting!
> 
> For the innocent readers, a correct average is:
> 
> (defun average (list) (and list (/ (reduce (function +) list) (length
> list))))

Could you elaborate on what you think is incorrect about my average
function? It was a joke, but I believe it is correct.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
From: Jon Harrop
Subject: Re: lisp function questions
Date: 
Message-ID: <433ca7b4$0$15035$ed2619ec@ptn-nntp-reader02.plus.net>
Jon Harrop wrote:
> The correct roots are roughly -1.0e+9 and 1.0e+9.

Oops. That should be -1e-9 and -1e9.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
From: Thomas A. Russ
Subject: Re: lisp function questions
Date: 
Message-ID: <ymi4q824iui.fsf@sevak.isi.edu>
Jon Harrop <······@jdh30.plus.com> writes:

> 
> Pascal Bourguignon wrote:
> > 
> > (defun average (list) (and list (/ (reduce (function +) list) (length
> > list))))
> 
> Could you elaborate on what you think is incorrect about my average
> function? It was a joke, but I believe it is correct.

I think it hinges on "correct".  The general rule of thumb is that if
you find yourself using EVAL when writing a Lisp function then you are
doing something wrong.  That goes double for new Lisp users.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: ·······@gmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128276141.886473.70820@z14g2000cwz.googlegroups.com>
Guys, thank you so much for the help!  It is really appreciated.
From: ·······@gmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128277399.732243.253350@g44g2000cwa.googlegroups.com>
In addition, I hope I did not stir up any trouble with this post.  I
really appreciate the different responses showing me different ways to
tackle this problem.  Infact I have learned a lot more here than just
how to solve this problem.  You guys in this group are great.  Thank
you.
From: Pascal Bourguignon
Subject: Re: lisp function questions
Date: 
Message-ID: <87y85eygzb.fsf@thalassa.informatimago.com>
Jon Harrop <······@jdh30.plus.com> writes:

> Pascal Bourguignon wrote:
>> There's no loop so there's no concern about numerical stability.
>
> Loops are irrelevant. There _is_ concern about numerical stability.
>
>> (defun solve-quadratic (a b c)
>>   (if (zerop a)
>>       (solve-linear b c)
>>       (let ((delta (- (* b b) (* 4 a c))))
>>         (delete-duplicates (list (/ (- (- b) (sqrt delta)) 2 a)
>>                                  (/ (+ (- b) (sqrt delta)) 2 a))
>>                            :test (function =)))))
>
> Consider why your code gives the wrong answer in this case:
>
> * (solve-quadratic 1d0 1d9 1d0)
> ;
>
> ; Warning: This function is undefined:
> ;   SOLVE-LINEAR
> ;
> (-1.0d+9 0.0d0)
>
> The correct roots are roughly -1.0e+9 and 1.0e+9. For more information, read
> Knuth's bible or my OCaml book. Quadratic solutions are a pedagogical
> example of numerical stability problems. Thus, if the person asking is an
> undergraduate, perhaps he is expected to give a better answer?

If you want more precision, ask for more precision:

[22]> (solve-quadratic 1L0 1L9 1L0)
(-9.99999999999999999L8 -9.895302355289459229L-10)

Note that: (and (float-equal -9.99999999999999999L8    -1.0d+9)
                (float-equal -9.895302355289459229L-10  0.0d0))

with: (defun float-equal (x y)
         (cond ((not (zerop y)) (< (abs (- 1 (/ x y))) 0.0001))
               ((not (zerop x)) (< (abs (- 1 (/ y x))) 0.0001))
               (t               t)))


> Could you elaborate on what you think is incorrect about my average
> function? It was a joke, but I believe it is correct.

It fails on lists longer than  CALL-ARGUMENTS-LIMIT  which may be as
small as 50, and it "fails" when the items in the list are not
self-evaluating, giving unsuspected results, like erasing your hard disk.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
From: Jon Harrop
Subject: Re: lisp function questions
Date: 
Message-ID: <433d1f63$0$16305$ed2619ec@ptn-nntp-reader01.plus.net>
Pascal Bourguignon wrote:
> If you want more precision, ask for more precision:
> 
> [22]> (solve-quadratic 1L0 1L9 1L0)
> (-9.99999999999999999L8 -9.895302355289459229L-10)
> 
> Note that: (and (float-equal -9.99999999999999999L8    -1.0d+9)
>                 (float-equal -9.895302355289459229L-10  0.0d0))
> 
> with: (defun float-equal (x y)
>          (cond ((not (zerop y)) (< (abs (- 1 (/ x y))) 0.0001))
>                ((not (zerop x)) (< (abs (- 1 (/ y x))) 0.0001))
>                (t               t)))

Using more precision is generally the wrong answer to numerical stability
problems. Knuth's bible gives an excellent explanation.

In this case, you've still got 10% error even with extended precision, i.e.
one of your answers is correct to only two significant figures and you
can't easily tell which answer that is.

If you want to find a root at 1e-100 (an entirely reasonable float value),
you don't want to have to use 200-digit precision arbitrary floating-point
arithmetic. A numerically stable implementation will get an accurate answer
using only conventional floating point precision.

>> Could you elaborate on what you think is incorrect about my average
>> function? It was a joke, but I believe it is correct.
> 
> It fails on lists longer than  CALL-ARGUMENTS-LIMIT  which may be as
> small as 50,

Ok. It is 1152921504606846975 here.

> and it "fails" when the items in the list are not 
> self-evaluating, giving unsuspected results, like erasing your hard disk.

Subexpressions will be evaluated in advance without eval:

* (average (cons 1 (cons (print 2) (cons 3 (cons 4 nil)))))

2
5/2

-- 
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com
From: Steven M. Haflich
Subject: Re: lisp function questions
Date: 
Message-ID: <Jo4%e.850$sL3.734@newssvr13.news.prodigy.com>
Pascal Bourguignon wrote:
> Jon Harrop <······@jdh30.plus.com> writes:
>>1. The algorithm used to compute the roots of a quadratic is different for
>>different number types. In particular, different forms are used for
>>floating point arithmetic if you want numerical stability.
> 
> There's no loop so there's no concern about numerical stability.

Yes, but if one _had_ to choose between numerical stability and
emotional stability, which is more important?
From: Raymond Toy
Subject: Re: lisp function questions
Date: 
Message-ID: <sxdbr2aznf0.fsf@rtp.ericsson.se>
>>>>> "Pascal" == Pascal Bourguignon <····@mouse-potato.com> writes:

    Pascal> Jon Harrop <······@jdh30.plus.com> writes:
    >> ·······@gmail.com wrote:
    >>> Thank you for the help, I will continue working on this.  Also if there
    >>> are any other suggestions please feel free to continue posting.
    >> 
    >> I'm no Lisp programmer but:

    Pascal> Indeed.


    >> 1. The algorithm used to compute the roots of a quadratic is different for
    >> different number types. In particular, different forms are used for
    >> floating point arithmetic if you want numerical stability.

    Pascal> There's no loop so there's no concern about numerical stability.
    Pascal> In lisp, arithmetic operators are polymorphic:

    Pascal> (defun solve-quadratic (a b c)
    Pascal>   (if (zerop a)
    Pascal>       (solve-linear b c)
    Pascal>       (let ((delta (- (* b b) (* 4 a c))))
    Pascal>         (delete-duplicates (list (/ (- (- b) (sqrt delta)) 2 a)
    Pascal>                                  (/ (+ (- b) (sqrt delta)) 2 a))
    Pascal>                            :test (function =)))))

If the coefficients are real and the roots are real, there is a
problem with numerical stability.  If 4*a*c is small, delta will be
close to b^2.  When you compute -b+sqrt(delta) (for b > 0) , you'll be
subtracting two numbers that are nearly equal.  Thus, most books
suggest computing this second root as c/<first root>.  The first root
doesn't have a round-off issue.

Ray
From: Pascal Bourguignon
Subject: Re: lisp function questions
Date: 
Message-ID: <87br2ay7yz.fsf@thalassa.informatimago.com>
Raymond Toy <···········@ericsson.com> writes:

>>>>>> "Pascal" == Pascal Bourguignon <····@mouse-potato.com> writes:
>
>     Pascal> Jon Harrop <······@jdh30.plus.com> writes:
>     >> ·······@gmail.com wrote:
>     >>> Thank you for the help, I will continue working on this.  Also if there
>     >>> are any other suggestions please feel free to continue posting.
>     >> 
>     >> I'm no Lisp programmer but:
>
>     Pascal> Indeed.
>
>
>     >> 1. The algorithm used to compute the roots of a quadratic is different for
>     >> different number types. In particular, different forms are used for
>     >> floating point arithmetic if you want numerical stability.
>
>     Pascal> There's no loop so there's no concern about numerical stability.
>     Pascal> In lisp, arithmetic operators are polymorphic:
>
>     Pascal> (defun solve-quadratic (a b c)
>     Pascal>   (if (zerop a)
>     Pascal>       (solve-linear b c)
>     Pascal>       (let ((delta (- (* b b) (* 4 a c))))
>     Pascal>         (delete-duplicates (list (/ (- (- b) (sqrt delta)) 2 a)
>     Pascal>                                  (/ (+ (- b) (sqrt delta)) 2 a))
>     Pascal>                            :test (function =)))))
>
> If the coefficients are real and the roots are real, there is a
> problem with numerical stability.  If 4*a*c is small, delta will be
> close to b^2.  When you compute -b+sqrt(delta) (for b > 0) , you'll be
> subtracting two numbers that are nearly equal.  Thus, most books
> suggest computing this second root as c/<first root>.  The first root
> doesn't have a round-off issue.

Thanks.

Anyway, I think it was more an exercice in lisp than in numerical recipe.

-- 
"You question the worthiness of my code? I should kill you where you
stand!"
From: ··············@hotmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128097141.854288.44950@g43g2000cwa.googlegroups.com>
Jon Harrop wrote:
>
> 2. I came up with this hideous concoction:
>
> * (defun average (list) (/ (eval (cons '+ list)) (length list)))
>
> AVERAGE
> * (average '(1 2 3 4))
>
> 5/2

Finally, to elaborate on Pascal's point on security, which you probably
missed because you are doing all these things from the read-eval-print
loop, here's a more explicit demonstration of the security pitfalls of
using eval on general lists.

;;; bad-eval.lisp
;;;
;;;

(defun bad-average (list)
  (/ (eval (cons '+ list)) (length list)))

(defun better-average (list)
  (/ (apply #'+ list) (length list)))

(defun get-number-list (input-stream)
  "Quick demo of getting a Lisp list from unreliable source."
  (format t "Welcome to my web site.~%Enter numbers, type :DONE when
done~%")
  (let ((*read-eval* nil)) ; protect against #. at least
    (do (num
         (list nil (cons num list)))
        ((eql num :DONE) (progn (format t "Thank you!!~%")
                                (nreverse (cdr list))))
; discard DONE, put back in order
      (format t "Enter number: ")
      (setf num (read input-stream)))))
;; SHOULD NOT USE READ in general

(defun test-bad-eval (string)
  (let ((num-list (get-number-list (make-string-input-stream string))))
    (progn
      (format t "Testing better average: ")
      (format t "~A~%"
              (ignore-errors (better-average num-list)))
;; make at least one thing robust...
      (format t "Testing bad average:")
      (format t "~A~%"
              (ignore-errors (bad-average num-list))))))



;;;; verification


(test-bad-eval "1
2
3
:DONE
")

(test-bad-eval "1
2
(progn (format t \"~%GOTCHA~%\") 3)
:DONE
")
From: ··············@hotmail.com
Subject: Re: lisp function questions
Date: 
Message-ID: <1128047232.292769.29400@g49g2000cwa.googlegroups.com>
·······@gmail.com wrote:
...
> My other function I am having trouble with is:
> a function that goes through a list and calculates the average of all
> numerica entries that appear somewhere inside the list.
>
> (defun average (m)
> (/ (+ m) (length m))
> )
>
> But I have to only count numeric entries. Also I do not think I am
> taking the sum of the list correctly. Any help would be greatly
> appreciated. Thanks!

Some others have suggested answers to your question, but I believe they
may have missed some essential points in the problem you are supposed
to solve.

First, consider what it means to have an expression (+ a b c)

It works if a, b, and c are variables with numbers as values. I.e., the
function + takes numbers and returns numbers.

What if the value of a, b, or c is not a number, but something like a
string or symbol? The function + does not work on those quantities,
only on numbers. Is m a number in your example?

Secondly, you mention "I have to only count numeric entries." This is
somewhat unusual, but perhaps typical for a introductory exercise. In
particular, by "list" do you mean possibly a list which contains other
lists? And are you supposed to count the numeric entries within the
sublists? Lisp programmers would think of that more as a "tree" than a
simple "list." Some of the answers (such as those using the function
reduce) suggested by others will not work if the list contains
non-numbers.

It seems likely your function is supposed to walk through the tree
structure. For each "leaf" in the tree (i.e. something that is an
"atom"), you should inspect it, to see if it is a number, and if so,
add it to the running sum of numbers you have seen so far. Also, you
should take into account that the number of elements in the sum has
been increased by one. There are a couple ways to do this.

Don't forget to look inside the lists-within-lists, if that is indeed
what your function is supposed to do.

Keep in mind that for problems like you were having with (+ m), you can
experiment at the Lisp prompt with small expressions until you are
comfortable, before you combine these expressions to form a function.

Good luck.