From: Sungwoo, Lim
Subject: Q: Optimisation of code.
Date: 
Message-ID: <111220002038255135%sungwoo@cad.strath.ac.uk>
Hello,

I saw this kind of code from some lisp tutorials, I think.
But I cannot remember it, so I wrote this...
It works, but looks untidy.
Could anyone give some more optimised suggestion please?
Thanks for your help. =)

Sungwoo


(if (< i 10)
  (cond ((= i 1) (setf b "st"))
        ((= i 2) (setf b "nd"))
        ((= i 3) (setf b "rd"))
        (t (setf b "th")))
  (cond ((= (rem i 10) 1) (setf b "st"))
        ((= (rem i 10) 2) (setf b "nd"))
        ((= (rem i 10) 3) (setf b "rd"))
        (t (setf b "th"))))
(if (< j 10)
  (cond ((= j 1) (setf d "st"))
        ((= j 2) (setf d "nd"))
        ((= j 3) (setf d "rd"))
        (t (setf b "th")))
  (cond ((= (rem j 10) 1) (setf d "st"))
        ((= (rem j 10) 2) (setf d "nd"))
        ((= (rem j 10) 3) (setf d "rd"))
        (t (setf d "th"))))

From: Johann Hibschman
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <mtr93eacbp.fsf@astron.berkeley.edu>
Sungwoo, Lim writes:

> Hello,
> I saw this kind of code from some lisp tutorials, I think.
> But I cannot remember it, so I wrote this...
> It works, but looks untidy.
> Could anyone give some more optimised suggestion please?
> Thanks for your help. =)

I'm assuming that there was a "b" for "d" swap in the case for j = 3.
I'm not sure what you mean by optimized.  I can write it in ways that
I find clearer, but I don't think the performance can be much altered.

I'd write this as

(setf b (case (rem i 10)
          (1 "st")
          (2 "nd")
          (3 "rd")
          (otherwise "th")))  
(setf d (case (rem j 10)
          (1 "st")
          (2 "nd")
          (3 "rd")
          (otherwise "th")))

or, under the principle of never repeating code,

(flet ((ordinal-ending (n)
         (case (rem n 10)
           (1 "st")
           (2 "nd")
           (3 "rd")
           (otherwise "th"))))
   (setf b (ordinal-ending i))
   (setf d (ordinal-ending j)))

I don't understand why that initial "if" was there in both cases.  I
can't imagine an implementation where that would actually be
relevantly faster than just "rem".

-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Sungwoo, Lim
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <111220002135010295%sungwoo@cad.strath.ac.uk>
In article <··············@astron.berkeley.edu>, Johann Hibschman
<······@physics.berkeley.edu> wrote:

> 
> I'm assuming that there was a "b" for "d" swap in the case for j = 3.
> I'm not sure what you mean by optimized.  I can write it in ways that
> I find clearer, but I don't think the performance can be much altered.

What I mean optimisation is 'tidy up' of the code. =)

> or, under the principle of never repeating code,
> 
> (flet ((ordinal-ending (n)
>          (case (rem n 10)
>            (1 "st")
>            (2 "nd")
>            (3 "rd")
>            (otherwise "th"))))
>    (setf b (ordinal-ending i))
>    (setf d (ordinal-ending j)))
> 

Thanks alot. =)
Sungwoo
From: Barry Margolin
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <fdbZ5.22$WO.472@burlma1-snr2>
In article <··························@cad.strath.ac.uk>,
Sungwoo, Lim <·······@cad.strath.ac.uk> wrote:
>Hello,
>
>I saw this kind of code from some lisp tutorials, I think.
>But I cannot remember it, so I wrote this...
>It works, but looks untidy.
>Could anyone give some more optimised suggestion please?
>Thanks for your help. =)

I don't understand why you need cases for less than 10, since you perform
the same tests in both cases.  (rem 1 10) is 1, isn't it?

It would be better if you didn't keep calling REM over and over.  If you
write it using CASE, this will only be computed once.  So what you want is:

(setf b
      (case (rem i 10)
        (1 "st")
        (2 "nd")
        (3 "rd")
        (t "th")))

However, although this is equivalent to the code you wrote, it doesn't seem
correct.  It will produce 11st, 12nd, and 13rd.  11, 12, and 13 are
exceptions to the general rule you've written: they should be 11th, 12th,
13th.  So the correct code should be:

(setf b
      (if (and (>= i 11) (<= i 13))
          "th"
	  (case (rem i 10)
	    (1 "st")
	    (2 "nd")
	    (3 "rd")
	    (t "th"))))

>  (cond ((= i 1) (setf b "st"))
>        ((= i 2) (setf b "nd"))
>        ((= i 3) (setf b "rd"))
>        (t (setf b "th")))
>  (cond ((= (rem i 10) 1) (setf b "st"))
>        ((= (rem i 10) 2) (setf b "nd"))
>        ((= (rem i 10) 3) (setf b "rd"))
>        (t (setf b "th"))))
>(if (< j 10)
>  (cond ((= j 1) (setf d "st"))
>        ((= j 2) (setf d "nd"))
>        ((= j 3) (setf d "rd"))
>        (t (setf b "th")))
>  (cond ((= (rem j 10) 1) (setf d "st"))
>        ((= (rem j 10) 2) (setf d "nd"))
>        ((= (rem j 10) 3) (setf d "rd"))
>        (t (setf d "th"))))


-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Sungwoo, Lim
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <111220002109187125%sungwoo@cad.strath.ac.uk>
In article <···············@burlma1-snr2>, Barry Margolin
<······@genuity.net> wrote:


> I don't understand why you need cases for less than 10, since you perform
> the same tests in both cases.  (rem 1 10) is 1, isn't it?
> 
> It would be better if you didn't keep calling REM over and over.  If you
> write it using CASE, this will only be computed once.  So what you want is:
> 
> (setf b
>       (case (rem i 10)
>         (1 "st")
>         (2 "nd")
>         (3 "rd")
>         (t "th")))
> 
> However, although this is equivalent to the code you wrote, it doesn't seem
> correct.  It will produce 11st, 12nd, and 13rd.  11, 12, and 13 are
> exceptions to the general rule you've written: they should be 11th, 12th,
> 13th.  So the correct code should be:
> 
> (setf b
>       (if (and (>= i 11) (<= i 13))
>           "th"
>           (case (rem i 10)
>             (1 "st")
>             (2 "nd")
>             (3 "rd")
>             (t "th"))))
> 

Aha! Yes, it is...
Also, I miss the 11th, 12th, and 13th point.
Thanks alot. ^_^

Sungwoo
From: Janis Dzerins
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <87n1e2yq0c.fsf@asaka.latnet.lv>
Barry Margolin <······@genuity.net> writes:

> (setf b
>       (if (and (>= i 11) (<= i 13))
>           "th"
> 	  (case (rem i 10)
> 	    (1 "st")
> 	    (2 "nd")
> 	    (3 "rd")
> 	    (t "th"))))

Couldn't resist:

(setf b
  (if (<= 11 i 13) ; this line changed :)
      "th"
    (case (rem i 10)
      (1 "st")
      (2 "nd")
      (3 "rd")
      (t "th"))))

Janis Dzerins
-- 
  If million people say a stupid thing it's still a stupid thing.
From: Sungwoo, Lim
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <121220001030498644%sungwoo@cad.strath.ac.uk>
In article <··············@asaka.latnet.lv>, Janis Dzerins
<·····@latnet.lv> wrote:

>  (<= 11 i 13)

Cool~~~ :)

Thanks,
Sungwoo
From: Pekka P. Pirinen
Subject: Re: Q: Optimisation of code.
Date: 
Message-ID: <ixr93d8p3g.fsf@harlequin.co.uk>
Barry Margolin <······@genuity.net> writes:
> 11, 12, and 13 are exceptions to the general rule you've written:
> they should be 11th, 12th, 13th.  So the correct code should be:
> 
> (setf b
>       (if (and (>= i 11) (<= i 13))
>           "th"
> 	  (case (rem i 10)
> 	    (1 "st")
> 	    (2 "nd")
> 	    (3 "rd")
> 	    (t "th"))))

Also, 111, 112, 113, 211, etc. are exceptions.  So that condition
should be (<= 11 (rem i 100) 13).  I think that's all the exceptions.

To avoid reinventing the wheel, one could use:

  (let ((st (format nil "~:R" i)))
    (subseq st (- (length st) 2)))

But that's a pretty expensive way of calculating this.
-- 
Pekka P. Pirinen, Adaptive Memory Management Group, Harlequin Limited
          "A computer lets you make more mistakes faster than any
invention in human history, with the possible exceptions of handguns
and tequila."        Mitch Ratliffe, _Technology Review_ April, 1992