From: Ken Tilton
Subject: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <W56ih.588$3o1.436@newsfe10.lga>
OK, right up front: you pointy-head intellectual language geniuses can 
spare me the floating-point lecture cr*p. I am a simple application 
programmer and I need seven point frickin two*.

To start with, let's take some arbitrary Lisp garbage like 7.2000003 and 
  just count the meaningful decimal places, in this case (and in the 
case of 7.19999997) just one. Think about it. You see that garbage, you 
know what is going on: 3.14799999999? Easy: 3.148. Why can't Lisp*** 
figure that out?! <sigh>

To be safe, we want a maximum number of places in case some yobbo passes 
in pi or (/ 1 3). And where we start with a computation**, we can /tell/ 
the function exactly the maximum by adding the decimal places of each 
multiplicand. Forgot that word, didn't you? But then we need to be able 
to count the places of the multiplicands, turtles all the way down and 
all that.

Be careful: 3.1234509 is pretty close to 3.12345 absolutely speaking, 
but that is not the kind of garbage produced by Lisp floating-point 
errors. And for god's sake make sure your code works on negative values 
as well as positive.

Are you crying? There's no crying in code challenges! And it's only a 
six-line loop, pretty simple at that, an order of magnitude easier than 
my other challenges.**** But I blew the 1.499999 case first time round, 
so I thought it would be fun for noobs to try.

My version way down below the sig.

ken

ps. how long a string of 0's or 9's tell me Lisp has screwed up? Let's 
make that a parameter, too. k

* Because the results are for human consumption. This is an educational 
application, right? Do I have to explain everything?!

** Makes me wonder if this ever comes up absent a computation.

*** Just hoping some pedantic language know-it-all says... wait, I 
better not give it away.

**** The best part? This is real live code I am running into on merit 
day in and day out. Eat your hearts out. :)

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon








































(defun decimal-places (f &optional (discriminator -3) (max 6)
                         &aux (discriminant (expt 10 discriminator)))
   (loop for places upfrom 0
       for place-value = (expt 10 places)
       while (< places max)
       when (< (abs (- (* f place-value) (round (* f place-value))))
              discriminant) do (loop-finish)
       finally (return places)))

From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-CF71D3.00411020122006@news.gha.chartermi.net>
In article <·················@newsfe10.lga>,
 Ken Tilton <·········@gmail.com> wrote:

> Why can't Lisp*** figure that out?!

Because Lisp doesn't have a decimal type (like Python now does).

>  <sigh>

Indeed.

rg
From: Frode Vatvedt Fjeld
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <2h64c6alhr.fsf@vserver.cs.uit.no>
In article <·················@newsfe10.lga>, Ken Tilton <·········@gmail.com> wrote:

> > Why can't Lisp*** figure that out?!

Ron Garret <·········@flownet.com> writes:

> Because Lisp doesn't have a decimal type (like Python now does).

Why would you want a decimal type if you already have rationals? (I'm
not being rhetorical here.)

What I suspect is that most people who write e.g. "1.02" really want
the object 102/100. So implementations should support
*read-default-float-format* RATIONAL. Conversely it would be nice to
have something like *print-pretty-ratio-format* "~,3F".

-- 
Frode Vatvedt Fjeld
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <V5cih.6$Ry.1@newsfe10.lga>
Frode Vatvedt Fjeld wrote:
> In article <·················@newsfe10.lga>, Ken Tilton <·········@gmail.com> wrote:
> 
> 
>>>Why can't Lisp*** figure that out?!
> 
> 
> Ron Garret <·········@flownet.com> writes:
> 
> 
>>Because ...


OK, people, the three *** footnote I withheld said "Just hoping someone 
is daft enought to take me seriously and explain about floating-point". 
Congratulations to everyone down there in that trap, sit tight, we're 
looking for a ladder now.

<sigh> This is an educational app. They get to type in their own 
problems. The answer to 2.4 * 3 is 7.2, not 7.20000003. The functional 
requirement (ie, no pedantic floating-point lectures required) is, when 
they then offer seven point frickin two as their answer, is to not say 
"Oh, you were so frickin close! Sorry!!!" And if the program generates 
an exmaple such as 3*2.4 and the student asks it to demonstrate, we need 
to show the correct effin result.

Actually, eventually I have to worry about significant digits, but I am 
not sure about how to handle that since most people want 2000+1 -> 2001, 
with 2000. being assumed. Probably will need an explicit mode.

Cleaned up a little (since the dog ate all your homeworks):

(defun decimal-places (f &optional (discriminator -3) (max 6) &aux 
(discriminant (expt 10 discriminator)))
   (loop for places upfrom 0
       for shifted-value = f then (* 10 f)
       while (< places max)
       when (< (abs (- shifted-value (round shifted-value))) discriminant)
       do (loop-finish)
       finally (return places)))

Ok, here is a question for you pedants: can the discriminant be a 
constant? Is that what single-float-epsilon is for? But then it does 
have to be a parameter, because it depends on where a number came from: 
the reader? 2.4 * 3? 2.4 * 1.5 * 2? Questions? Comments?

  You gotta love Lisp, it even puts its bugs in the standard. "It is OK 
to blow the arithmetic, just tell us how much."***

kenny

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Tim Bradshaw
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166633194.070823.103770@n67g2000cwd.googlegroups.com>
Ken Tilton wrote:

> <sigh> This is an educational app. They get to type in their own
> problems. The answer to 2.4 * 3 is 7.2, not 7.20000003. The functional
> requirement (ie, no pedantic floating-point lectures required) is, when
> they then offer seven point frickin two as their answer, is to not say
> "Oh, you were so frickin close! Sorry!!!" And if the program generates
> an exmaple such as 3*2.4 and the student asks it to demonstrate, we need
> to show the correct effin result.
>

What is the right answer when they type in 20 divided by 3?  6.67?
6.66? 6.667? 6.7? 7? 20/3  Based on experience with a fairly large
number of such questions in recent history (dealing with school-age
children) you need to phrase the question as `give the answer as a
decimal, to two significant figures' or similar.  Then you do a careful
comparison of the answers (I can describe what that is, but I need to
think: basically you want to carefully round to the right number of SFs
in each case, and compare).
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <N9eih.22$7r7.12@newsfe11.lga>
Tim Bradshaw wrote:
> Ken Tilton wrote:
> 
> 
>><sigh> This is an educational app. They get to type in their own
>>problems. The answer to 2.4 * 3 is 7.2, not 7.20000003. The functional
>>requirement (ie, no pedantic floating-point lectures required) is, when
>>they then offer seven point frickin two as their answer, is to not say
>>"Oh, you were so frickin close! Sorry!!!" And if the program generates
>>an exmaple such as 3*2.4 and the student asks it to demonstrate, we need
>>to show the correct effin result.
>>
> 
> 
> What is the right answer when they type in 20 divided by 3?  6.67?
> 6.66? 6.667? 6.7? 7? 20/3  

Not 6.6 with a bar over the last 6? Anyway:

20/3 or 6-and-2/3

This is Algebra so we do not have to mess with conversion between 
fractions and decimals and we do not want to discard precision for 
notation's sake.

> Based on experience with a fairly large
> number of such questions in recent history (dealing with school-age
> children) you need to phrase the question as `give the answer as a
> decimal, to two significant figures' or similar.

If enough schools ask for that I might consider it, before telling them 
to go take a flying leap. I'd rather get started on Algebra II and Trig. 
Kids do not have much trouble with converting 1/3 to .333..., so we 
foucs the scarce kenny resource on the backbreaker: multi-transformation 
solutions involving abstract quantities and many possible applicable 
rules at any one step.

otoh, your comments just got you onto my mailing list, focus group, and 
beta test team. welcome aboard. (you picked the wrong day to wash the 
helicopters.)

kt

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Tim Bradshaw
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166695365.514094.207910@79g2000cws.googlegroups.com>
Ken Tilton wrote:
> (you picked the wrong day to wash the
> helicopters.)

I thought you were on helicopter-washing duty this week?  I know I was
on the making-primadonna-programmers-into-soap shift.  Damn, I'll have
to check the rota: I'm worried that no one has been allocated to the
spreading-implausible-stories-about-terrorist-plots job, again.

--tim
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <0IFih.119$fl7.40@newsfe08.lga>
Tim Bradshaw wrote:
> Ken Tilton wrote:
> 
>>(you picked the wrong day to wash the
>>helicopters.)
> 
> 
> I thought you were on helicopter-washing duty this week?  I know I was
> on the making-primadonna-programmers-into-soap shift.  Damn, I'll have
> to check the rota: I'm worried that no one has been allocated to the
> spreading-implausible-stories-about-terrorist-plots job, again.

Cheney might be able to pick up the slack on that. Lemme check his 
disappearance schedule...

kt

-- 
The Dalai Lama gets the same crap all the time.
   -- Kenny Tilton on c.l.l when accused of immodesty
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-43C0E6.12070820122006@newsclstr02.news.prodigy.com>
In article <························@n67g2000cwd.googlegroups.com>,
 "Tim Bradshaw" <··········@tfeb.org> wrote:

> Ken Tilton wrote:
> 
> > <sigh> This is an educational app. They get to type in their own
> > problems. The answer to 2.4 * 3 is 7.2, not 7.20000003. The functional
> > requirement (ie, no pedantic floating-point lectures required) is, when
> > they then offer seven point frickin two as their answer, is to not say
> > "Oh, you were so frickin close! Sorry!!!" And if the program generates
> > an exmaple such as 3*2.4 and the student asks it to demonstrate, we need
> > to show the correct effin result.

Wrap the numbers in rationalize?

CL-USER> (* (rationalize 2.4) (rationalize 3))
36/5
CL-USER> (float (* (rationalize 2.4) (rationalize 3)))
7.2

Is there a lisp library for reducing fractions?  

And for irrationals like pi, I'd give them the value with the number 
of significant digits. So pi=3.142.

> What is the right answer when they type in 20 divided by 3?  6.67?
> 6.66? 6.667? 6.7? 7? 20/3  Based on experience with a fairly large
> number of such questions in recent history (dealing with school-age
> children) you need to phrase the question as `give the answer as a
> decimal, to two significant figures' or similar.  Then you do a careful
> comparison of the answers (I can describe what that is, but I need to
> think: basically you want to carefully round to the right number of SFs
> in each case, and compare).

I think in most of my higher math we simplified to rational 
expressions. So we would leave expressions at 3pi, (2x)/3 and 
sqrt(2).

Personally. I'd go a bit more fuzzy and set lower and upper bounds. 
Of course, as one of those evil inquiry-based math people a teaching 
moments on different ways to round numbers might be interesting. 

7.200 < 2.4*3 < 7.210: 

That's probably a bit too broad but...
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tkvb41hypqzri1@pandora.upc.no>
> Is there a lisp library for reducing fractions?
>

Not to my knowlege,  but it would be fairly trivial to write one.

First create a base 10 representation for the number.

.2 = 2/10
.22222... = 2/9
Note with a finite number of digits you are really guessing here.

So all numbers with either a fixed number of digits or with infinite  
repitition
after a given sequenc of digits (really the same .2 = .2000... = 2/10  
+ 1/10 * 0/9)
can be representated.

2.718281828..
27/10 + 1/10 * 1828/9999
You can then collect the factors.
Note also you probably guessed wrong here. It looks like e which is in  
fact transendental
and never repeats. 2.71828182890459023536.. if I remember correctly.

With all these limitations, are you still sure you want it?

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-0CD206.13555120122006@newsclstr03.news.prodigy.net>
In article <·················@pandora.upc.no>,
 "John Thingstad" <··············@chello.no> wrote:

> I wrote
> > Is there a lisp library for reducing fractions?
> >
> 
> Not to my knowlege,  but it would be fairly trivial to write one.
> 
> First create a base 10 representation for the number.

I was actually thinking more directly from a ratio representation of 
a number, which would be only approximate in the case of irrational 
numbers. 

I actually figured out you can do it with truncate: A rather quick 
and sloppy:

(defun reduce-fraction (ratio-num)
         (multiple-value-bind (num rem) 
            (truncate (numerator ratio-num) (denominator ratio-num))
          (values num (/ rem (denominator ratio-num))))) 

REDUCE-FRACTION
CL-USER> (reduce-fraction -36/5)
-7
-1/5

Of course, this doesn't work as well for pi, but I wouldn't expect 
it to.

CL-USER> (reduce-fraction (rationalize pi))
3
11080585/78256779
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-016@Yahoo.Com>
> From: Kirk  Sluder <····@nospam.jobsluder.net>
> Wrap the numbers in rationalize?
> CL-USER> (* (rationalize 2.4) (rationalize 3))
> 36/5

That (exactly as you show it) works only for literals within source
code, and only when the number of significant digits is small
compared to the precision of the floating point numbers used
internally. To the second point:
* (rationalize 2.7)
27/10      ;Correct
* (rationalize 2.718281828)
2721/1001  ;Not what you wanted!
To the first point, the student will *not* be writing Lisp source
code, which will be read by READ. The student will be filling text
into a form, which only needs READ-FROM-STRING if you want to screw
yourself, but instead PARSE-RATIONAL if you want to do the right
thing. When you first get started, you can fake PARSE-RATIONAL as
just rationalize of READ-FROM-STRING, which will work so long as
the student never types more than a few significant digits.
After you have the rest of your program working, if you want to
allow for unlimited number of significant digits in student's
input, you can simply re-define PARSE-RATIONAL to really do the
correct thing, without changing the rest of your program that calls
it.

> Is there a lisp library for reducing fractions?

What are you talking about? Common Lisp automatically maintains all
rational numbers in reduced form already. If you divide two
integers, it reduces the result before returning the result to the
caller. Likewise if you divide two rationals.
If you have an explicit not-reduced fraction as separate numerator
and denominator, you simply divide them to get the reduced
fraction.
You don't need a library. It's built in!

Note that so-far the OP has mentionned only multiplication and
addition, no division, so with exact rational input which happens
to come from exact decimal-fraction syntax typed in, the output
rational number will also be expressible exactly in
decimal-fraction syntax.

If and when the OP expresses an interest in division, or irrational
numbers such as sqrt(2) or pi, then we can broaden the discussion.
But so far all his use cases deal with only exact decimal-fraction
input and only multiplication and addition. I think we should stick
with the use cases he's asked about, and not try to guess all the
other bells and whistles we might wish to add which he hasn't asked
for.
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-0669EA.12204425122006@newsclstr02.news.prodigy.com>
In article <·················@Yahoo.Com>,
 ·······@Yahoo.Com (Robert Maas, see http://tinyurl.com/uh3t) 
 wrote:

> That (exactly as you show it) works only for literals within source
> code, and only when the number of significant digits is small
> compared to the precision of the floating point numbers used
> internally. To the second point:
> * (rationalize 2.7)
> 27/10      ;Correct
> * (rationalize 2.718281828)
> 2721/1001  ;Not what you wanted!

Well, to start with, it's not my program.

Secondly.  I think the goal was to reduce the errors produced by 
math operations using a small number of significant digits compared 
to the underlying float representation. .  So 2721/1001 may 
certainly be called for if (* 3 2721/1001) returns a result with the 
proper number of significant digits. 

As for reducing fractions, what I was seeking was a way to display 
something like 10/3 as 3 + 1/3 which can be useful when you are not 
working with a decimal form of measurement, and have problems doing 
the division and modulus in your head. I managed to muddle through 
to a function.
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec25-012@Yahoo.Com>
> From: Kirk  Sluder <····@nospam.jobsluder.net>
> Well, to start with, it's not my program.

Is it a program somebody else wrote, but did a bad job, it doesn't
work properly, and now you are trying to fix it to work better?

> I think the goal was to reduce the errors produced by math
> operations using a small number of significant digits compared to
> the underlying float representation.

Do you have the option to change that underlying representation to
something more appropriate, such as rationals?

> So 2721/1001 may certainly be called for if (* 3 2721/1001)
> returns a result with the proper number of significant digits.

If you're *never* going to do any subtraction, nor the equivalent
adding of positive and negative numbers together, then you may
survive. But you must know already that whenever you subtract two
quantities (or add numbers of opposite sign) you end up with fewer
significant digits than you started, and in fact you can end up
with not even one significant digit, in fact you can end up with a
result orders of magnitude wrong. You do know that, don't you??

So if there's *any* way for students to enter an effective
subtraction, then storing input values as approximate (not exactly
correct) floating-point values is *not* acceptable, will *not*
assure you of even one significant digit in the final answer, not
even an order-of-magnitude-correct ballpark-approximation, even if
floating-point approimations are immediately coverted to exact or
best-guess rationals (via RATIONAL or RATIONALIZE respectively) and
all subsequent calculations are done in rationals. You *must* parse
all input directly into exactly-correct rationals if students can
provoke an effective subtraction.

Now a different topic:
> As for reducing fractions, what I was seeking was a way to
> display something like 10/3 as 3 + 1/3 ...

If you capture input as exact rationals (equal exactly to the
decimal-fractions entered), but then do division (thereby resulting
in rationals which are *not* equal to any decimal fraction), so you
choose to express these values as mixed common fractions instead of
as approximate decimal fractions or as improper common fractions,
the task is trivial:
1: Test the value to see if it's an integer. If so, format it
directly as an integer.
2: Otherwise, test whether the absolute value is less than 1. If
so, format it directly as a rational.
3: Otherwise, test whether it's positive (greater than 1) or
negative (less than -1), and use FLOOR or CEILING respectively to
pull out the integer part as first value, or for negative values
take additive inverse and call FLOOR, and format the second value
as a rational. Or don't do any test, just call TRUNCATE and express
the result in a uniform way:
  RATIONAL VALUE: -22/7       22/7
  FLOOR:                      3 1/7
  CEILING:        -3 -1/7
  NEG-FLOOR:      -(3 1/7)
  TRUNCATE:       -3 -1/7     3 1/7
If you can display results in 2-d ASCII-art mode (similar to how
MacSyma and MRPP4 display such values), you would see something
like:       1         1           1
       - 3 ---  -3 - ---       3 ---
            7         7           7
Of course if you have true graphic fraction bars and proportional
fonts (like MRPP3) you can make each 2-d notation prettier.
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-E8D416.23241925122006@newsclstr02.news.prodigy.com>
In article <·················@Yahoo.Com>,
 ·······@Yahoo.Com (Robert Maas, see http://tinyurl.com/uh3t) 
 wrote:

> > From: Kirk  Sluder <····@nospam.jobsluder.net>
> > Well, to start with, it's not my program.
> 
> Is it a program somebody else wrote, but did a bad job, it doesn't
> work properly, and now you are trying to fix it to work better?

I was making a suggestion for the author of the original post, who 
was asking for suggestions on how to avoid working with 
floating-point errors from math problems entered by students.
 
> > I think the goal was to reduce the errors produced by math
> > operations using a small number of significant digits compared to
> > the underlying float representation.
> 
> Do you have the option to change that underlying representation to
> something more appropriate, such as rationals?

That was my suggestion. Rather than perform the math as (* (float 3) 
(float 2.4)) to perform the math as (* (rationalize 3) (rationalize 
2.4)).  I don't see what your objection here is.
 
> > So 2721/1001 may certainly be called for if (* 3 2721/1001)
> > returns a result with the proper number of significant digits.
> 
> If you're *never* going to do any subtraction, nor the equivalent
> adding of positive and negative numbers together, then you may
> survive. But you must know already that whenever you subtract two
> quantities (or add numbers of opposite sign) you end up with fewer
> significant digits than you started, and in fact you can end up
> with not even one significant digit, in fact you can end up with a
> result orders of magnitude wrong. You do know that, don't you??

Well, actually I've never heard or read about this. I've always seen 
and worked with the rule that your significant figures is limited by 
your least accurate measurement. Could you provide an example?

Conversion of input into rationals is not expected to replace 
intelligence checks on the part of the student. Only to avoid the 
problem encountered by the OP:

CL-USER> (* 3 2.4)
7.2000003
CL-USER> 
 
> So if there's *any* way for students to enter an effective
> subtraction, then storing input values as approximate (not exactly
> correct) floating-point values is *not* acceptable, will *not*
> assure you of even one significant digit in the final answer, not
> even an order-of-magnitude-correct ballpark-approximation, even if
> floating-point approimations are immediately coverted to exact or
> best-guess rationals (via RATIONAL or RATIONALIZE respectively) and
> all subsequent calculations are done in rationals. You *must* parse
> all input directly into exactly-correct rationals if students can
> provoke an effective subtraction.

Could you explain more? Do you have any examples where these 
functions would yield results different from what would be expected?  
Under what conditions would this cause problems?
From: Johan Ur Riise
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <871wmbjxz2.fsf@morr.riise-data.net>
·······@Yahoo.Com (Robert Maas, see http://tinyurl.com/uh3t) writes:

> like:       1         1           1
>        - 3 ---  -3 - ---       3 ---
>             7         7           7

(defun format-rational-yes (rational)
  (let ((abs-rational (abs rational)))
    (multiple-value-bind (integer rest) (truncate abs-rational)
      (let* ((negative (when (< rational 0) t))
             (numerator (numerator rest))
             (denominator (denominator rest))
             (integer-string (format nil "~d" integer))
             (numerator-string (format nil "~d" numerator))
             (denominator-string (format nil "~d" denominator))
             (fraction-length (max (length numerator-string) (length denominator-string)))
             )
        (loop 
           repeat (+ (if negative 2 0)
                     (length integer-string)
                     1
                     1
                     (truncate fraction-length 2)
                     (- (truncate (length numerator-string) 2)))
           do 
             (princ " "))
        (princ numerator-string)
        (terpri)
        (when negative (princ "- "))
        (princ integer-string)
        (princ " ")
        (loop repeat (+ 2 fraction-length) do (princ "-"))
        (terpri)
        (loop 
           repeat (+ (if negative 2 0)
                     (length integer-string)
                     1
                     1
                     (truncate fraction-length  2)
                     (- (truncate (length denominator-string) 2))) 
           do
             (princ " ")) 
        (princ denominator-string)
        (terpri)))))

CL-USER> (format-rational-yes 3476/60)
    14
57 ----
    15
NIL

CL-USER> (format-rational-yes (- (+ 1 72/22)))
      3
- 4 ----
     11
NIL
From: Madhu
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <m3ac0zvtl8.fsf@robolove.meer.net>
[The obligatory FORMAT-string version follows]

* Johan Ur Riise  <··············@morr.riise-data.net> :
|
| (defun format-rational-yes (rational)
|   (let ((abs-rational (abs rational)))
|     (multiple-value-bind (integer rest) (truncate abs-rational)
|       (let* ((negative (when (< rational 0) t))
|              (numerator (numerator rest))
|              (denominator (denominator rest))
|              (integer-string (format nil "~d" integer))
|              (numerator-string (format nil "~d" numerator))
|              (denominator-string (format nil "~d" denominator))
|              (fraction-length (max (length numerator-string)
|                           (length denominator-string))) )
|         (loop
|            repeat (+ (if negative 2 0)
|                      (length integer-string)
|                      1
|                      1
|                      (truncate fraction-length 2)
|                      (- (truncate (length numerator-string) 2)))
|            do
|              (princ " "))
|         (princ numerator-string)
|         (terpri)
|         (when negative (princ "- "))
|         (princ integer-string)
|         (princ " ")
|         (loop repeat (+ 2 fraction-length) do (princ "-"))
|         (terpri)
|         (loop
|            repeat (+ (if negative 2 0)
|                      (length integer-string)
|                      1
|                      1
|                      (truncate fraction-length  2)
|                      (- (truncate (length denominator-string) 2)))
|            do
|              (princ " "))
|         (princ denominator-string)
|         (terpri)))))


(defun reduce-fraction (rational)
  "Return as values SIGNUM WHOLE NUMERATOR DENOMINATOR of given RATIONAL."
  (let ((sign (signum rational)))
    (setq rational (* rational sign))	; abs
    (let ((denominator (denominator rational)))
      (multiple-value-bind (whole remainder)
	  (truncate (numerator rational) denominator)
	(unless (zerop remainder)
	  (setq remainder (/ remainder denominator)))
	(values sign whole (numerator remainder) (denominator remainder))))))

(defun ndigits (integer)
  "Return the number of decimal digits in INTEGER."
  (loop for x = (truncate integer 10) then (truncate x 10)
        count 1
	until (zerop x)))

(defun format-rational-yes (rational &optional (stream t))
  (multiple-value-bind (signum whole num den) (reduce-fraction rational)
    (let* ((divlen (max (ndigits num) (ndigits den)))
	   (padlen (+ 1 divlen (if (< signum 0) 1 0) (ndigits whole))))
      (format stream ·······@[~C~]~D ~v,,,'-,@a~%~vD~%"  padlen num
	      (if (< signum 0) #\-) whole divlen #\-  padlen den))))

CL-USER> (format-rational-yes 3476/60)
   14
57 --
   15
NIL
CL-USER> (format-rational-yes (- (+ 1 72/22)))
    3
-4 --
   11
NIL


 Question for the FORMAT wizards: How should ·@[ ~] interact with a ~V
 DIRECTIVE which is contained inside of it?

 For example, in :

(format nil ··@[~vD~]" nil nil)
(format nil ··@[~vD~]" nil 10)

--
Madhu
From: Raymond Toy
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <sxdfyaqoalm.fsf@rtp.ericsson.se>
>>>>> "Madhu" == Madhu  <·······@meer.net> writes:

    Madhu> (defun reduce-fraction (rational)
    Madhu>   "Return as values SIGNUM WHOLE NUMERATOR DENOMINATOR of given RATIONAL."
    Madhu>   (let ((sign (signum rational)))
    Madhu>     (setq rational (* rational sign))	; abs
    Madhu>     (let ((denominator (denominator rational)))
    Madhu>       (multiple-value-bind (whole remainder)
    Madhu> 	  (truncate (numerator rational) denominator)
    Madhu> 	(unless (zerop remainder)
    Madhu> 	  (setq remainder (/ remainder denominator)))
    Madhu> 	(values sign whole (numerator remainder) (denominator remainder))))))

How about something like:

(defun reduce-fraction (rational)
  (let ((sign (signum rational)))
    (multiple-value-bind (whole frac)
	(truncate (abs rational))
      (values sign whole (numerator frac) (denominator frac)))))

Ray
From: Johan Ur Riise
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <87odpej0oj.fsf@morr.riise-data.net>
Madhu <·······@meer.net> writes:

> [The obligatory FORMAT-string version follows]
> 
> (defun reduce-fraction (rational)
>   "Return as values SIGNUM WHOLE NUMERATOR DENOMINATOR of given RATIONAL."
>   (let ((sign (signum rational)))
>     (setq rational (* rational sign))	; abs
>     (let ((denominator (denominator rational)))
>       (multiple-value-bind (whole remainder)
> 	  (truncate (numerator rational) denominator)
> 	(unless (zerop remainder)
> 	  (setq remainder (/ remainder denominator)))
> 	(values sign whole (numerator remainder) (denominator remainder))))))
> 
> (defun ndigits (integer)
>   "Return the number of decimal digits in INTEGER."
>   (loop for x = (truncate integer 10) then (truncate x 10)
>         count 1
> 	until (zerop x)))
> 
> (defun format-rational-yes (rational &optional (stream t))
>   (multiple-value-bind (signum whole num den) (reduce-fraction rational)
>     (let* ((divlen (max (ndigits num) (ndigits den)))
> 	   (padlen (+ 1 divlen (if (< signum 0) 1 0) (ndigits whole))))
>       (format stream ·······@[~C~]~D ~v,,,'-,@a~%~vD~%"  padlen num
> 	      (if (< signum 0) #\-) whole divlen #\-  padlen den))))
> 
> CL-USER> (format-rational-yes 3476/60)
>    14
> 57 --
>    15
> NIL
> CL-USER> (format-rational-yes (- (+ 1 72/22)))
>     3
> -4 --
>    11
> NIL
> 

Great, its shorter, but not quite up to spec;

(format-rational-yes 100/1000000000001) ;mine
        100
0 ---------------
   1000000000001
NIL

(format-rational-yes+ 100/1000000000001) ;yours
            100
0 -------------
  1000000000001
NIL

And worse (both versions)


(format-rational-yes+ 23)
   0
23 -
   1
NIL

there is no fraction, it should not be printed.
From: Madhu
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <m364bmwjl4.fsf@robolove.meer.net>
Helu
* Johan Ur Riise <··············@morr.riise-data.net> :
|
| Great, its shorter, but not quite up to spec;
|
| (format-rational-yes 100/1000000000001) ;mine
|         100
| 0 ---------------
|    1000000000001
| NIL
|
| (format-rational-yes+ 100/1000000000001) ;yours
|             100
| 0 -------------
|   1000000000001
| NIL

FORMAT does not have any directives to align text in the center that I
am aware of. Another question for the FORMAT wizards.

| And worse (both versions)
|
| (format-rational-yes+ 23)
|    0
| 23 -
|    1
| NIL
|
| there is no fraction, it should not be printed.

Unfortunately this can be fixed with a more hideous format string! We
can also omit printing a 0 `Whole' - so that we also get:

CL-USER> (format-rational-yes -23/100)
   23
- ---
  100


(defun format-rational-yes (rational &optional (stream t))
  (multiple-value-bind (signum whole num den) (reduce-fraction rational)
    (let* ((divlen (if (zerop num) 0 (max (ndigits num) (ndigits den))))
           (padlen (+ 1 divlen (if (< signum 0) 1 0)
                      (if (zerop whole) 0 (ndigits whole)))))
      (format stream
   "~:[~vD~;~*~*~]···@[~C~]~:[~D ~;~* ~]~:[~v,,,'-,@a~;~*~*~]~%~:[~vD~;~*~*~]~%"
              (zerop num) padlen num
              (if (< signum 0) #\-) (zerop whole) whole (zerop num) divlen #\-
              (zerop num) padlen den))))

--
Madhu :)
From: Thomas A. Russ
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <ymisleqfctr.fsf@sevak.isi.edu>
Madhu <·······@meer.net> writes:

> FORMAT does not have any directives to align text in the center that I
> am aware of. Another question for the FORMAT wizards.

~< ... ~>  does alignment.  Try the following:

  (format nil ······@<~A~>|" 'foo)

The gory details:

http://www.lispworks.com/documentation/HyperSpec/Body/22_cfb.htm

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tloqgelipqzri1@pandora.upc.no>
On Thu, 04 Jan 2007 22:47:03 +0100, Madhu <·······@meer.net> wrote:

Wrote a function printf->format last year:

http://groups.google.se/group/comp.lang.lisp/browse_thread/thread/9bfc9c9f9a789dea/014b73e976f1d6d2?lnk=gst&q=printf&rnum=3#014b73e976f1d6d2

If you look at integer-dispatch or float dispatch you will see
a example of using '~<' notation for formatting.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2007jan06-004@Yahoo.Com>
> From: Johan Ur Riise <····@riise-data.no>
>   (defun format-rational-yes (rational)
[snipped two full VT-100 screens of source code]

Hey, that's a good start! I tried it here in CMUCL and it worked
just fine for the two examples you gave. Then I tried it for two
easier examples and it didn't exactly give what the student would
like to see:

* (format-rational-yes 5)
   0
5 ---
   1
NIL

* (format-rational-yes -2/7)
     2
- 0 ---
     7

I suppose you can call a higher level function that checks for
integer, and calls format-rational-yes only in case of integer.
I suppose the higher-level function would be called format-rational,
which explains the "yes" in the name of your function.

But in the case of proper fraction with zero integer part, where
you do *not* want the extra 0 at the front, there's no way to get
around the bug except by duplicating most your effort in another
function that omits the integer part, or taking the trouble to fix
the bug in your algorithm by testing for zero integer part and
suppressing the integer printout and the corresponding whitespace
above and below.

Two other style quibbles:
- You wrote it as one large function, two full VT-100 screens, so
it's impossible on VT-100 dialup to see the whole function at one
time. Per modern programming style, it would be nice if the
functionality could be split into separate sub-functions plus a
toplevel master function.
- It writes directly to an output stream, rather than generating a
rectangular array and then writing it at the last moment. This
would make it slightly painful to embed this print-representation
inside a larger expression such as a polynomial (after all the OP
said this was for a high-school *algebra* class, not fifth-grade
arithmetic class). To convert the output of this print function
into a rectangular array, the most obvious method is to:
  - Embed the call in something like with-output-to-string.
  - Parse the string per newline delimiters to break it into a
     vector of single-line strings, but computing the maximum
     line-length and padding all shorter lines to that maximum.
At that point we have in effect a rectangular block which can then
be embedded into larger rectangular virtual-block or picture-block
objects. (Virtual block is a structure that contains explicit links
to smaller picture-blocks such as created above or virtual-blocks,
plus x,y offsets from origin of overall block to each contained
block, plus x,y sizes for the overall block. Picture block is just
an ascii-art block given as a fully padded rectangular array
implemented as vector of strings.)

Alternately, by re-writing the code, the print representation could
be generated directly in a nested structure of virtual blocks, with
picture blocks only for the smallest elements of the picture (the
minus sign, the integer part, the numerator, the fraction bar, and
the denominator). Then when you need to actually output something,
you traverse the structure building up single-line segments, for
example in your case the top line has just the indented numerator,
the middle line has the minus sign and integer part and fraction
bar, and the bottom part has the indented denominator, and then
each single-line segment is printed with TAB commands between
consecutive non-adjacent parts. So this breaks up the functionality
to where you first build the nested virtual block (of arbitrary
complexity) bottom-up, then you convert your toplevel block into
virtual multi-segment output lines, then you actually print the
sequence of output lines.

My program MRPP3 (circa 1975) basically did that, where the virtual
blocks were called "overlays", borrowing notation from plastic
sheets with images on each which can be overlayed on top of each
other when viewing through an overhead-projector. It used a
bitraster device (XGP = Xerox Graphics Printer), so there weren't
print lines as with a pure ascii-art print format. Instead the
system device driver required all the individual pieces of text and
graphics to be sorted sequentially down the page according to the
*first* (topmost) scanline of each. But within any set of atomic
pieces that all started at the same scanline, such as two
consecutive numerators (in the same font) in a sum of fractions,
the pieces could be in any sequence. So the building of nested
overlay structure with offsets from each container overlay to its
components was basically the same as I described above except for
counting font metrics for height and width of each atomic text
overlay, and then the traversal converted it to a list of lists of
atomic pieces sorted by topmost scanline, and then the data was
just dumped to the output channel with explicit *absolute* offsets
for each atomic piece instead of tabs from end of one piece to
start of next. Gosper's MRPP3-macros that expanded into MRPP3
commands to build overlays of various mathematical pictures given a
nesting of calls to such macros, plus Gosper's MacLISP program to
convert from nested-lists (using MacSyma representation I believe)
to nested-macro syntax, plus MRPP3 then expanding the macros to a
bottom-up sequence of overlay-building commands and then executing
those commands to actually build the overlay and print it,
accomplished the overall objective. (P.S. due to political powers
that be at SAIL, MRPP3 had been renamed POX a while before Gosper
started building his library of macros, so maybe you know them as
POX macros instead.)

Note: MRPP4, a rewrite of that in PSL, for ASCII output did
basically what I described earlier, while for VM/CMS displays and
Unix X window system displays it did more like MRPP3.

Anyway, I still think "overlays" (or virtual rectangular blocks)
are a really good idea for expressing nested pictures of
mathematical or tabular etc. objects, and I wish TeX and HTML
supported them. Does anybody have a Common Lisp package that builds
such nested virtual-image structures then displays/prints them
later?

Oh, one super advantage of keeping explicit nested structure
instead of solid verbatim rectangular blocks is that if you need to
display such a picture on a device that isn't wide enough to
accomodate it all, it's easy to prettyprint it with linebreaks.
For example, something that prints all in one piece on 80-character screen:
  1     2     3     4     5     6     7     8     9    10    11    12
 --- - --- + --- - --- + --- - --- + --- - --- + --- - --- + --- - --- + ...
  2     5     8    11    14    17    20    23    26    29    32    35
On a narrower screen should look like this:
  1     2     3     4     5     6 
 --- - --- + --- - --- + --- - ---
  2     5     8    11    14    17 

    7     8     9    10    11    12
 + --- - --- + --- - --- + --- - --- + ...
   20    23    26    29    32    35
which can easily be accomplished by a smart
nested-virtual-rectangle prettyprinter. But if you instead just
spew the data out linearily, and let Lisp's linelength break up the
lines, you would get this garbage output:
  1     2     3     4     5     6   
  7     8     9    10    11    12
 --- - --- + --- - --- + --- - ---
 + --- - --- + --- - --- + --- - --- + ...
  2     5     8    11    14    17 
   20    23    26    29    32    35
So you see the big win of nested overlays (virtual blocks) if you
want to format arbitrarily complicated math on a device that has a
strict limit on width of the display? Even on a windows system
where you can make a scrollable window as large virtually as you
want, still it'd be a pain for the student to have to scroll back
and forth back and forth back and forth just to see all the parts
of a very very wide expression. Better to prettyprint within a
strict window width that matches physical hardware width.

Unfortunately I and my MRPP3/MRPP4 users are the only people who
ever expressed an interest in automatic conversion of nested
mathematical expressions such as
 (plus (expt 1/4 -1) (/ (+ x 5) (- y 2)))
in 2-d visual format. I'd like to write a Web demo of such
presentation, but HTML doesn't quite support nested overlays, and
in Lynx (the only Web browser usable from here) even the crude HTML
tables aren't supported, so I'd have to generate
<pre>asciiart</pre> displays that work only with fixed-pitch fonts,
and there's no funding or interest, so I'm probably not going to bother.
From: Johan Ur Riise
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <877ivxhvaf.fsf@morr.riise-data.net>
·······@Yahoo.Com (Robert Maas, see http://tinyurl.com/uh3t) writes:

> > From: Johan Ur Riise <····@riise-data.no>
> >   (defun format-rational-yes (rational)
> [snipped two full VT-100 screens of source code]
> 
> Hey, that's a good start! I tried it here in CMUCL and it worked
> just fine for the two examples you gave. Then I tried it for two
> easier examples and it didn't exactly give what the student would

interesting, but you really need to modernize your equipment.
From: robert maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rem-2007jan21-008@yahoo.com>
> From: Johan Ur Riise <····@riise-data.no>
> > >   (defun format-rational-yes (rational)
> > [snipped two full VT-100 screens of source code]
> >
> > Hey, that's a good start! I tried it here in CMUCL and it worked
> > just fine for the two examples you gave. Then I tried it for two
> > easier examples and it didn't exactly give what the student would
> interesting, but you really need to modernize your equipment.

Well if you would hire me to work for you, and pay me enough money
to pay off my credit-card debts, and also pay me enough money on a
regular basis that I could move to a decent sized apartment where
such extra equipment would fit, and also pay me enough to afford
such equipment...
From: Pascal Bourguignon
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <87ac0bq4ns.fsf@thalassa.informatimago.com>
·······@yahoo.com (robert maas, see http://tinyurl.com/uh3t) writes:

>> From: Johan Ur Riise <····@riise-data.no>
>> > >   (defun format-rational-yes (rational)
>> > [snipped two full VT-100 screens of source code]
>> >
>> > Hey, that's a good start! I tried it here in CMUCL and it worked
>> > just fine for the two examples you gave. Then I tried it for two
>> > easier examples and it didn't exactly give what the student would
>> interesting, but you really need to modernize your equipment.
>
> Well if you would hire me to work for you, and pay me enough money
> to pay off my credit-card debts, and also pay me enough money on a
> regular basis that I could move to a decent sized apartment where
> such extra equipment would fit, and also pay me enough to afford
> such equipment...

Modern equipment is more miniaturized.  You'll need LESS space.

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

CAUTION: The mass of this product contains the energy equivalent of
85 million tons of TNT per net ounce of weight.
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tku7k0ujpqzri1@pandora.upc.no>
On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com> wrote:

>
>   You gotta love Lisp, it even puts its bugs in the standard. "It is OK  
> to blow the arithmetic, just tell us how much."***
>
> kenny
>

This is no bug. It is impossible to describe a irrational/trancendental
number with a finite number of digits.
Further the numbers which can be represented eactly will vary with
the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
but not in a binary whith only prime 2.
1/4 = 0.25 has no roundoff error.
But performing the transform is rather trivial and the performance
penalty of using decimal representation would make it useless for many
applications.
It is standard in all computation to give a error value epsilon and then  
check
that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
If you don't want your students to worry about it you will just have
to set one for them. 10^-6 should be fine I guess.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <badih.11$Ry.8@newsfe10.lga>
John Thingstad wrote:
> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com> wrote:
> 
>>
>>   You gotta love Lisp, it even puts its bugs in the standard. "It is 
>> OK  to blow the arithmetic, just tell us how much."***
>>
>> kenny
>>
> 
> This is no bug...


AAAAAUUUAUUSUUUGUUHUUHUHUUGHGGHGHGH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: ·········@juno.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166642634.840304.284350@79g2000cws.googlegroups.com>
John Thingstad wrote:
> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com> wrote:
>
> >
> >   You gotta love Lisp, it even puts its bugs in the standard. "It is OK
> > to blow the arithmetic, just tell us how much."***
> >
> > kenny
> >
>
> This is no bug. It is impossible to describe a irrational/trancendental
> number with a finite number of digits.
> Further the numbers which can be represented eactly will vary with
> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
> but not in a binary whith only prime 2.
> 1/4 = 0.25 has no roundoff error.
> But performing the transform is rather trivial and the performance
> penalty of using decimal representation would make it useless for many
> applications.
> It is standard in all computation to give a error value epsilon and then
> check
> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
> If you don't want your students to worry about it you will just have
> to set one for them. 10^-6 should be fine I guess.
>
> --
> Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

You're right.  It's clearly impossible:
perl -e "print 2.4*3;"
7.2

--S
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-27C25B.15155120122006@newsclstr03.news.prodigy.net>
In article <························@79g2000cws.googlegroups.com>,
 ·········@juno.com wrote:

> You're right.  It's clearly impossible:
> perl -e "print 2.4*3;"
> 7.2

CL-USER> (format t "~1$" (* 2.4 3))
7.2
NIL
CL-USER> 

> 
> --S
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tkvi62sdpqzri1@pandora.upc.no>
On Wed, 20 Dec 2006 20:23:54 +0100, <·········@juno.com> wrote:

> John Thingstad wrote:
>> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com>  
>> wrote:
>>
>> >
>> >   You gotta love Lisp, it even puts its bugs in the standard. "It is  
>> OK
>> > to blow the arithmetic, just tell us how much."***
>> >
>> > kenny
>> >
>>
>> This is no bug. It is impossible to describe a irrational/trancendental
>> number with a finite number of digits.
>> Further the numbers which can be represented eactly will vary with
>> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
>> but not in a binary whith only prime 2.
>> 1/4 = 0.25 has no roundoff error.
>> But performing the transform is rather trivial and the performance
>> penalty of using decimal representation would make it useless for many
>> applications.
>> It is standard in all computation to give a error value epsilon and then
>> check
>> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
>> If you don't want your students to worry about it you will just have
>> to set one for them. 10^-6 should be fine I guess.
>>
>> --
>> Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
>
> You're right.  It's clearly impossible:
> perl -e "print 2.4*3;"
> 7.2
>
> --S
>

so it pretties up the result..

You are aware that .99999.. = 1 ?

so (* 3 2.4) = 7.199999.. = 7.2

As I said in sted of calculating in decimals you can fix it to the closest
number on the decimal line. That dosn't mean that you should use = to  
compare
floating point calculations however.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: ·········@juno.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166647277.316711.293180@t46g2000cwa.googlegroups.com>
John Thingstad wrote:
> On Wed, 20 Dec 2006 20:23:54 +0100, <·········@juno.com> wrote:
>
> > John Thingstad wrote:
> >> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com>
> >> wrote:
> >>
> >> >
> >> >   You gotta love Lisp, it even puts its bugs in the standard. "It is
> >> OK
> >> > to blow the arithmetic, just tell us how much."***
> >> >
> >> > kenny
> >> >
> >>
> >> This is no bug. It is impossible to describe a irrational/trancendental
> >> number with a finite number of digits.
> >> Further the numbers which can be represented eactly will vary with
> >> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
> >> but not in a binary whith only prime 2.
> >> 1/4 = 0.25 has no roundoff error.
> >> But performing the transform is rather trivial and the performance
> >> penalty of using decimal representation would make it useless for many
> >> applications.
> >> It is standard in all computation to give a error value epsilon and then
> >> check
> >> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
> >> If you don't want your students to worry about it you will just have
> >> to set one for them. 10^-6 should be fine I guess.
> >>
> >> --
> >> Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
> >
> > You're right.  It's clearly impossible:
> > perl -e "print 2.4*3;"
> > 7.2
> >
> > --S
> >
>
> so it pretties up the result..
>
> You are aware that .99999.. = 1 ?
>
> so (* 3 2.4) = 7.199999.. = 7.2
>
> As I said in sted of calculating in decimals you can fix it to the closest
> number on the decimal line. That dosn't mean that you should use = to
> compare
> floating point calculations however.
>
> --
> Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

I am aware that after conversion to binary 2.4*3 != 7.2, but both C
and perl print the output as 7.2.  I thought that was Ken's point, but
maybe I misunderstood.

Anyway, it's not just the result of a "pretty" output formatter.  Note:

perl -e 'print 7.20000000000001;'
7.20000000000001

-- S
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-C3E45F.15563420122006@newsclstr02.news.prodigy.com>
In article <························@t46g2000cwa.googlegroups.com>,
 ·········@juno.com wrote:

> I am aware that after conversion to binary 2.4*3 != 7.2, but both C
> and perl print the output as 7.2.  I thought that was Ken's point, but
> maybe I misunderstood.
> 
> Anyway, it's not just the result of a "pretty" output formatter.  Note:
> 
> perl -e 'print 7.20000000000001;'
> 7.20000000000001
> 
> -- S

perl -e "printf '%.20f', 7.20000000000001;"; echo ""
7.20000000000000994760

It looks like it is scaling the precision to the input.
From: ·········@juno.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166649745.262313.122910@t46g2000cwa.googlegroups.com>
Kirk Sluder wrote:
> In article <························@t46g2000cwa.googlegroups.com>,
>  ·········@juno.com wrote:
>
> > I am aware that after conversion to binary 2.4*3 != 7.2, but both C
> > and perl print the output as 7.2.  I thought that was Ken's point, but
> > maybe I misunderstood.
> >
> > Anyway, it's not just the result of a "pretty" output formatter.  Note:
> >
> > perl -e 'print 7.20000000000001;'
> > 7.20000000000001
> >
> > -- S
>
> perl -e "printf '%.20f', 7.20000000000001;"; echo ""
> 7.20000000000000994760
>
> It looks like it is scaling the precision to the input.


That's more of a bug.  Those last digits aren't
present in the machine representaion of the value.

perl -e 'print 7.2000000000000001==7.2?"Y":"N";'
Y

Adding one more zero hits the precision limit of floating point
in perl, which is whatever the C library supports on this
architecture.

If Ken is looking for ==, then he needs to use fixed point
arithmetic.  I think it was PL/1 that allowed fixed point
decimal, but you can do the equivalent in perl by printing
the value to a string, since perl allows strings and numbers
to be used interchangeably.
-- S
From: ············@gmail.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166689517.806499.281250@48g2000cwx.googlegroups.com>
Kirk Sluder wrote:
> perl -e "printf '%.20f', 7.20000000000001;"; echo ""
> 7.20000000000000994760
>
> It looks like it is scaling the precision to the input.

Um, floats in perl are IEEE 754 double precision, which means that you
get < 16 decimal digits of precision (1 + epsilon == 1 for positive
epsilon < about 2.23 x 10^{-16}).  So if you try to print anything
after that, you'll probably get garbage.  printf should be smart enough
to realize that and stop you, but it doesn't.

Come on guys and gals, learn some stuff about floating-point, it's good
for you :)  There are a number of options besides the traditional IEEE
754 style binary floating point:

* Extended (variable) precision floating point:  see e.g. MPFR (Prof.
Fateman and I were working on a Lisp interface for MPFR -- anybody want
to help us finish it?)
* so-called "exact real arithmetic" based on continued fractions (see
e.g. Gosper; a while back there was a Lisp implementation available,
not sure about the status of that)
* FLI arithmetic (good for problems with huge numerical ranges, but
poor precision at the extreme ends of the representable range)

All of these have implementations; it's a programming exercise to link
them to Lisp if they aren't in Lisp already.  Clisp already uses
something like MPFR for its LONG-FLOAT objects.

I'd suggest that if you want arithmetic to work sort of "like you
expect," just use MPFR objects, crank the precision really high and
only display the first few digits.  That's the easy way to get around
not knowing much numerical analysis.  (Hey, there's no shame in that;
Prof. Kahan of IEEE 754 fame estimated at a recent talk this year that
about one qualified numerical analyst is produced in the entire WORLD
each year.)

Poke me if you want some references on floating-point; I'd be glad to
give them to you.

mfh
From: ············@gmail.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166689519.635092.19820@n67g2000cwd.googlegroups.com>
Kirk Sluder wrote:
> perl -e "printf '%.20f', 7.20000000000001;"; echo ""
> 7.20000000000000994760
>
> It looks like it is scaling the precision to the input.

Um, floats in perl are IEEE 754 double precision, which means that you
get < 16 decimal digits of precision (1 + epsilon == 1 for positive
epsilon < about 2.23 x 10^{-16}).  So if you try to print anything
after that, you'll probably get garbage.  printf should be smart enough
to realize that and stop you, but it doesn't.

Come on guys and gals, learn some stuff about floating-point, it's good
for you :)  There are a number of options besides the traditional IEEE
754 style binary floating point:

* Extended (variable) precision floating point:  see e.g. MPFR (Prof.
Fateman and I were working on a Lisp interface for MPFR -- anybody want
to help us finish it?)
* so-called "exact real arithmetic" based on continued fractions (see
e.g. Gosper; a while back there was a Lisp implementation available,
not sure about the status of that)
* FLI arithmetic (good for problems with huge numerical ranges, but
poor precision at the extreme ends of the representable range)

All of these have implementations; it's a programming exercise to link
them to Lisp if they aren't in Lisp already.  Clisp already uses
something like MPFR for its LONG-FLOAT objects.

I'd suggest that if you want arithmetic to work sort of "like you
expect," just use MPFR objects, crank the precision really high and
only display the first few digits.  That's the easy way to get around
not knowing much numerical analysis.  (Hey, there's no shame in that;
Prof. Kahan of IEEE 754 fame estimated at a recent talk this year that
about one qualified numerical analyst is produced in the entire WORLD
each year.)

Poke me if you want some references on floating-point; I'd be glad to
give them to you.

mfh
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-017@Yahoo.Com>
> From: ·········@juno.com
> perl -e 'print 7.20000000000001;'
> 7.20000000000001

That's only because perl defaults to round to nearest 15
significant digits when printing. But try a number whose exact
value requires just one more significant digit, and watch perl give
an incorrect printout:

perl -e 'print 7.200000000000036;'
7.20000000000004
perl -e 'print 2.718281828459045;'
2.71828182845905
perl -e 'print 3.141592653589793;'
3.14159265358979
perl -e 'print 500 + 2.718281828459045;'
502.718281828459
perl -e 'print 1E14 + 2.718281828459045;'
100000000000003
perl -e 'print 1E14 + 2.718281828459045 - 1E14;'
2.71875
;That isn't even correct to the next-to-last place printed!!
;Perhaps you should stop worshipping perl.

Back to Lisp:
* (setq m1 (parse-rational "2.4"))
12/5
* (setq m2 (parse-rational "3"))
3
* (setq prod (* m1 m2))
36/5
* (setq big (expt 10 14))
100000000000000
* (+ big prod)
500000000000036/5
* (- * big)
36/5
* (format-interval * 30)
"7.200000000000000000000000000000"
* (string-right-trim "0" *)
"7.2"
* (setq ee (parse-rational "2.718281828459045"))
543656365691809/200000000000000
* (+ big *)
20000000000000543656365691809/200000000000000
* (format-interval * 30)
"100000000000002.718281828459045000000000000000"
* (- ** big)
543656365691809/200000000000000
* (format-interval * 30)
"2.718281828459045000000000000000"
* (string-right-trim "0" *)
"2.718281828459045"
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-8378A0.15351420122006@newsclstr03.news.prodigy.net>
In article <·················@pandora.upc.no>,
 "John Thingstad" <··············@chello.no> wrote:

> On Wed, 20 Dec 2006 20:23:54 +0100, <·········@juno.com> wrote:

> > You're right.  It's clearly impossible:
> > perl -e "print 2.4*3;"
> > 7.2
> >
> > --S
> >
> 
> so it pretties up the result..

A quick search reveals that perl does in fact filter floats through 
printf() according to some obscure default parameters:

perl -e "printf '%.16f', 2.4*3;"; echo ""
7.1999999999999993
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tku7nux0pqzri1@pandora.upc.no>
On Wed, 20 Dec 2006 16:49:38 +0100, John Thingstad  
<··············@chello.no> wrote:

> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com>  
> wrote:
>
>>
>>   You gotta love Lisp, it even puts its bugs in the standard. "It is OK  
>> to blow the arithmetic, just tell us how much."***
>>
>> kenny
>>
>
> This is no bug. It is impossible to describe a irrational/trancendental
> number with a finite number of digits.
> Further the numbers which can be represented eactly will vary with
> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
> but not in a binary whith only prime 2.
> 1/4 = 0.25 has no roundoff error.
> But performing the transform is rather trivial and the performance
> penalty of using decimal representation would make it useless for many
> applications.
> It is standard in all computation to give a error value epsilon and then  
> check
> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
> If you don't want your students to worry about it you will just have
> to set one for them. 10^-6 should be fine I guess.
>

To misquote Naggum: If real number calculations don't meet your  
expectations
please adjust your expectations. :)

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <tbdih.12$Ry.5@newsfe10.lga>
John Thingstad wrote:
> On Wed, 20 Dec 2006 16:49:38 +0100, John Thingstad  
> <··············@chello.no> wrote:
> 
>> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com>  
>> wrote:
>>
>>>
>>>   You gotta love Lisp, it even puts its bugs in the standard. "It is 
>>> OK  to blow the arithmetic, just tell us how much."***
>>>
>>> kenny
>>>
>>
>> This is no bug. It is impossible to describe a irrational/trancendental
>> number with a finite number of digits.
>> Further the numbers which can be represented eactly will vary with
>> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
>> but not in a binary whith only prime 2.
>> 1/4 = 0.25 has no roundoff error.
>> But performing the transform is rather trivial and the performance
>> penalty of using decimal representation would make it useless for many
>> applications.
>> It is standard in all computation to give a error value epsilon and 
>> then  check
>> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
>> If you don't want your students to worry about it you will just have
>> to set one for them. 10^-6 should be fine I guess.
>>
> 
> To misquote Naggum: If real number calculations don't meet your  
> expectations
> please adjust your expectations. :)
> 

We're gonna need a bigger ladder.

kenny

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <Aedih.13$Ry.4@newsfe10.lga>
John Thingstad wrote:
> On Wed, 20 Dec 2006 16:49:38 +0100, John Thingstad  
> <··············@chello.no> wrote:
> 
>> On Wed, 20 Dec 2006 15:50:38 +0100, Ken Tilton <·········@gmail.com>  
>> wrote:
>>
>>>
>>>   You gotta love Lisp, it even puts its bugs in the standard. "It is 
>>> OK  to blow the arithmetic, just tell us how much."***
>>>
>>> kenny
>>>
>>
>> This is no bug. It is impossible to describe a irrational/trancendental
>> number with a finite number of digits.
>> Further the numbers which can be represented eactly will vary with
>> the number system 0.2 = 1/5 fine in a decimal system with primes 2 and 5
>> but not in a binary whith only prime 2.
>> 1/4 = 0.25 has no roundoff error.
>> But performing the transform is rather trivial and the performance
>> penalty of using decimal representation would make it useless for many
>> applications.
>> It is standard in all computation to give a error value epsilon and 
>> then  check
>> that error < epsilon. So 1/4 = .25 is wrong 1/4 - 0.25 < epsilon right.
>> If you don't want your students to worry about it you will just have
>> to set one for them. 10^-6 should be fine I guess.
>>
> 
> To misquote Naggum: If real number calculations don't meet your  
> expectations
> please adjust your expectations. :)
> 

I figured it out. You all are clones of the same mindless Eliza program 
and this was one of the hard-codes!

<sigh>

kenny

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-015@Yahoo.Com>
> From: "John Thingstad" <··············@chello.no>
> To misquote Naggum: If real number calculations don't meet your
> expectations please adjust your expectations. :)

That's irrelevant to this thread. The OP is not using real number
calculations, he's using fixed-precision binary-floating-point
approximations to real numbers with round-off at input and
round-off at each intermediate calculation and round-off during
printing.

The correct quote per this thread is: If fixed-precision
binary-floating-point approximations to real numbers don't meet
your expectations, then use a different tool.
In this case, for the OP's educational application, rational
numbers are quite sufficient to express all input values exactly
and to perform all calculations exactly, so presumably that's the
tool he should have used.
From: Timofei Shatrov
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <45896e87.29990273@news.readfreenews.net>
On Wed, 20 Dec 2006 09:50:38 -0500, Ken Tilton <·········@gmail.com> tried to
confuse everyone with this message:

>
>
>Frode Vatvedt Fjeld wrote:
>> In article <·················@newsfe10.lga>, Ken Tilton <·········@gmail.com> wrote:
>> 
>> 
>>>>Why can't Lisp*** figure that out?!
>> 
>> 
>> Ron Garret <·········@flownet.com> writes:
>> 
>> 
>>>Because ...
>
>
>OK, people, the three *** footnote I withheld said "Just hoping someone 
>is daft enought to take me seriously and explain about floating-point". 
>Congratulations to everyone down there in that trap, sit tight, we're 
>looking for a ladder now.
>

He had a good suggestion actually. Just convert everything into rationals.
"rationalize" function is quite smart.

-- 
|Don't believe this - you're not worthless              ,gr---------.ru
|It's us against millions and we can't take them all... |  ue     il   |
|But we can take them on!                               |     @ma      |
|                       (A Wilhelm Scream - The Rip)    |______________|
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <Z5hih.26$eq5.18@newsfe09.lga>
Timofei Shatrov wrote:
> On Wed, 20 Dec 2006 09:50:38 -0500, Ken Tilton <·········@gmail.com> tried to
> confuse everyone with this message:
> 
> 
>>
>>Frode Vatvedt Fjeld wrote:
>>
>>>In article <·················@newsfe10.lga>, Ken Tilton <·········@gmail.com> wrote:
>>>
>>>
>>>
>>>>>Why can't Lisp*** figure that out?!
>>>
>>>
>>>Ron Garret <·········@flownet.com> writes:
>>>
>>>
>>>
>>>>Because ...
>>
>>
>>OK, people, the three *** footnote I withheld said "Just hoping someone 
>>is daft enought to take me seriously and explain about floating-point". 
>>Congratulations to everyone down there in that trap, sit tight, we're 
>>looking for a ladder now.
>>
> 
> 
> He had a good suggestion actually. Just convert everything into rationals.
> "rationalize" function is quite smart.
> 

Nothing like a good nap. I /do/ keep student-entered work as rationals. 
But to clone a problem involving decimals as the notation, I needed to 
give random a float, and it has been a while since I worked on this area 
of the app so the rational thing had been swapped out of warnock* and 
was not there to remind me to convert back to rational before using it.

it was a bug!

thx, ken

* mental cache

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Thomas A. Russ
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <ymiirg3hh18.fsf@sevak.isi.edu>
Ken Tilton <·········@gmail.com> writes:
>   You gotta love Lisp, it even puts its bugs in the standard. "It is OK
>   to blow the arithmetic, just tell us how much."***

Easier to find them there, than in the core dump file.  ;)

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-014@Yahoo.Com>
> From: Ken Tilton <·········@gmail.com>
> This is an educational app. They get to type in their own
> problems. The answer to 2.4 * 3 is 7.2 ...

How exactly do they enter such problems?
Do they type exactly "2.4 * 3" and you wrote your own infix parser,
and you were stupid enough to parse "2.4" as a float instead of as
a rational?
Or they type "2.4" into one text field, use a menu for the
operators, then type "3" into another text field, and you were
stupid enough to parse each text field using READ-FROM-STRING
(which by default parses "2.4" as a float instead of rational,
which you should have known already if you had RTFM) instead of
writing your own PARSE-RATIONAL to do what you really wanted?

> when they then offer seven point frickin two as their answer, is
> to not say "Oh, you were so frickin close! Sorry!!!"

How exactly do they enter their supposed correct answer (which you
compare with the computer-calculated truly-correct answer)?
Do they type in "7.2" into a text field, and your program stupidly
calls READ-FROM-STRING to generate a float, instead of doing the
right thing of calling PARSE-RATIONAL to generate a rational that
can be exactly compared with the rational computed from above? How
is that any fault except your own in poor program design?

> eventually I have to worry about significant digits, but I am not
> sure about how to handle that since most people want
> 2000+1 -> 2001 ...

Both of the addends, and the sum, are exact rationals, so
significant digits aren't relevant at all in checking the correct
answer, so I have no idea why you mention them here. If your
program doesn't get that one correct then you must be a very very
bad programmer!

> You gotta love Lisp, it even puts its bugs in the standard.

I'm not aware of any bug in rational-number arithmetic in Common
Lisp (which is what you should be using for this educational
      application),
either in the standard/spec nor in any implementation. If you know
of any, please give an example.
From: Johan Ur Riise
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <87fyark6kj.fsf@morr.riise-data.net>
·······@Yahoo.Com (Robert Maas, see http://tinyurl.com/uh3t) writes:

> ... writing your own PARSE-RATIONAL to do what you really wanted...

(in-package :cl-user)

(defun parse-rational (decimal-fraction-string)
  (let ((res 0)
        (before-comma t)
        (divisor 10)
        (negative nil))
    (loop for char across decimal-fraction-string do
         (let* ((decimal (position char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))))
           (if decimal 
               (if before-comma 
                   (setf res (+ (* 10 res) decimal))
                   (progn (setf res (+ res (/ decimal divisor)))
                          (setf divisor (* 10 divisor))))
               (cond  ((char= #\. char)
                       (setf before-comma nil))
                      ((char= #\- char)
                       (setf negative t))))))
    (when negative (setf res (- res)))
    res)))

(defun test () 
  (and (eql 10 (parse-rational "10"))
       (eql 100 (parse-rational "100"))
       (eql 10 (parse-rational "010"))
       (eql 10 (parse-rational "0000010"))
       (eql 1 (parse-rational "1."))
       (eql 1 (parse-rational "1.0"))
       (eql 1 (parse-rational "01.000"))
       (eql 0 (parse-rational "0."))
       (eql 3/2 (parse-rational "1.5"))
       (eql (- (+ 715 2/10 3/100)) (parse-rational "-715.23"))
       (eql (+ 715 2/10 3/100 345/1000000) (parse-rational "715.230345"))
       (eql (+ 715 2/10 3/100 345/1000000 33/1000000000000000000) (parse-rational "715.230345000000000033"))))

(defun test2 ()
  (let* ((a (parse-rational "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012"))
         (b (parse-rational "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030"))
         (c (+ a b))
         (d (- c 2))
         (e (parse-rational "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))
         (f (* d e)))
    f))

CL-USER> (parse-rational "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030")
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003/100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
CL-USER> (test2)
42


Yes, it _could_ have been done
From: Zach Beane
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <m3tzz74ml8.fsf@unnamed.xach.com>
Johan Ur Riise <·····@riise-data.no> writes:

>          (let* ((decimal (position char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))))
>            (if decimal 
[snip]

DIGIT-CHAR-P would be a little more succinct here.

Zach
From: Johan Ur Riise
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <8764bnk2bm.fsf@morr.riise-data.net>
Zach Beane <····@xach.com> writes:

> Johan Ur Riise <·····@riise-data.no> writes:
> 
> >          (let* ((decimal (position char '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))))
> >            (if decimal 
> [snip]
> 
> DIGIT-CHAR-P would be a little more succinct here.
> 
> Zach

Yes, didn't know that.

Ok, to reestablish symmetry:

(defun format-decimal-fraction (number &optional (stream *standard-output*))
  (when (< number 0) 
    (format stream "-")
    (setf number (abs number)))
  (multiple-value-bind (before-point remaining) (truncate number)
    (format stream "~d" before-point)
    (when (> remaining 0) (format stream "."))
    (loop repeat 1000 
       while (> remaining 0) do
         (let (digit)
           (multiple-value-setq (digit remaining) (truncate (*  remaining 10)))
           (format stream "~d" digit))))
  number)

CL-USER> (format-decimal-fraction (- (+ 20 77/100)))
-20.77
2077/100

CL-USER> (format-decimal-fraction (+ 1 (/ 1 (expt 10 20))))
1.00000000000000000001
100000000000000000001/100000000000000000000

CL-USER> (progn (format-decimal-fraction 2/3) (terpri))
0.6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666
NIL
From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-FE525D.11225720122006@news.gha.chartermi.net>
In article <··············@vserver.cs.uit.no>,
 Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

> In article <·················@newsfe10.lga>, Ken Tilton <·········@gmail.com> 
> wrote:
> 
> > > Why can't Lisp*** figure that out?!
> 
> Ron Garret <·········@flownet.com> writes:
> 
> > Because Lisp doesn't have a decimal type (like Python now does).
> 
> Why would you want a decimal type if you already have rationals? (I'm
> not being rhetorical here.)

Because people get confused when they see $199/50 instead of $3.98.

rg
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-769A45.14590920122006@newsclstr03.news.prodigy.net>
In article 
<·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:
> Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

>> Why would you want a decimal type if you already have rationals? 
>> (I'm not being rhetorical here.)
> Because people get confused when they see $199/50 instead of $3.98.

CL-USER> (format t "$~$" (float 199/50))
$3.98
???

Or, 

(defun money-fraction (ratio-num)
         (multiple-value-bind (num rem) 
            (truncate (numerator ratio-num) (denominator ratio-num))
          (values num (truncate (* 100 (/ rem (denominator 
ratio-num)))))))

The display issues are really quite trivial. At least according to 
the proposal document for decimal 
(http://www.python.org/dev/peps/pep-0327/) there were concerns about 
the underlying performance of ratios vs. decimals. 
 
> rg
From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-69FFCD.12544720122006@news.gha.chartermi.net>
In article <··························@newsclstr03.news.prodigy.net>,
 Kirk  Sluder <····@nospam.jobsluder.net> wrote:

> In article 
> <·······························@news.gha.chartermi.net>,
>  Ron Garret <·········@flownet.com> wrote:
> > Frode Vatvedt Fjeld <······@cs.uit.no> wrote:
> 
> >> Why would you want a decimal type if you already have rationals? 
> >> (I'm not being rhetorical here.)
> > Because people get confused when they see $199/50 instead of $3.98.
> 
> CL-USER> (format t "$~$" (float 199/50))
> $3.98
> ???

Heh, you learn something new every day.

rg
From: Frode Vatvedt Fjeld
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <2h1wmu9thd.fsf@vserver.cs.uit.no>
Frode Vatvedt Fjeld <······@cs.uit.no> wrote:
> > Why would you want a decimal type if you already have rationals? (I'm
> > not being rhetorical here.)

Ron Garret <·········@flownet.com> writes:

> Because people get confused when they see $199/50 instead of $3.98.

But isn't the presentation of something is separate from its internal
representation? If you present something using format and ~$, as would
be natural for dollar amounts, it doesn't matter if the representation
is float or rational. (format t "~$" 199/50) prints 3.98.

-- 
Frode Vatvedt Fjeld
From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-EA8731.13254120122006@news.gha.chartermi.net>
In article <··············@vserver.cs.uit.no>,
 Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

> Frode Vatvedt Fjeld <······@cs.uit.no> wrote:
> > > Why would you want a decimal type if you already have rationals? (I'm
> > > not being rhetorical here.)
> 
> Ron Garret <·········@flownet.com> writes:
> 
> > Because people get confused when they see $199/50 instead of $3.98.
> 
> But isn't the presentation of something is separate from its internal
> representation? If you present something using format and ~$, as would
> be natural for dollar amounts, it doesn't matter if the representation
> is float or rational. (format t "~$" 199/50) prints 3.98.

Yes, I didn't know about the ~$ format directive.

I'm still pondering the ramifications of allowing e.g. 1/3 of a dollar.

rg
From: Rob Warnock
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <G6udnRdy7pmUQRTYnZ2dnUVZ_uuqnZ2d@speakeasy.net>
Ron Garret  <·········@flownet.com> wrote:
+---------------
| Frode Vatvedt Fjeld <······@cs.uit.no> wrote:
| > Ron Garret <·········@flownet.com> writes:
| > > Because people get confused when they see $199/50 instead of $3.98.
| > 
| > But isn't the presentation of something is separate from its internal
| > representation? If you present something using format and ~$, as would
| > be natural for dollar amounts, it doesn't matter if the representation
| > is float or rational. (format t "~$" 199/50) prints 3.98.
| 
| Yes, I didn't know about the ~$ format directive.
| I'm still pondering the ramifications of allowing e.g. 1/3 of a dollar.
+---------------

The precision of ~$ only *defaults* to 2; you can specify another:

    (format nil "~$" 8/3)     ==> "2.67"
    (format nil "~1$" 8/3)    ==> "2.7"
    (format nil "~4$" 8/3)    ==> "2.6667"

Small "gotcha" to watch for: The ~$ format will [or, is allowed to]
coerce rationals to *single* floats, e.g.:

    (format nil "~20$" 8/3)   ==> "2.66666670000000000000"
    (format nil "~20$" (coerce 8/3 'double-float))
			      ==> "2.66666666666666650000"


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Frode Vatvedt Fjeld
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <2hwt4m8d74.fsf@vserver.cs.uit.no>
Ron Garret <·········@flownet.com> writes:

> Yes, I didn't know about the ~$ format directive.

But ~$ is not really essential to the point I was making. Rather, the
point was that there is obviously some transformation happening
between the float object (which is a fixed-size bit-pattern with
exponent, mantissa and so on) and the "3.98" string that eventually is
presented on the screen. Clearly that transformation can be changed
slightly to allow for rational input. So you can exchange ~F for ~$,
or any other conceivable presentation of real numbers (at least in
theory, if not in practice).

-- 
Frode Vatvedt Fjeld
From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-2885C6.14074120122006@news.gha.chartermi.net>
In article <··············@vserver.cs.uit.no>,
 Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > Yes, I didn't know about the ~$ format directive.
> 
> But ~$ is not really essential to the point I was making. Rather, the
> point was that there is obviously some transformation happening
> between the float object (which is a fixed-size bit-pattern with
> exponent, mantissa and so on) and the "3.98" string that eventually is
> presented on the screen. Clearly that transformation can be changed
> slightly to allow for rational input. So you can exchange ~F for ~$,
> or any other conceivable presentation of real numbers (at least in
> theory, if not in practice).

There are two separate issues, but they are not orthogonal.  The issue 
of how things are represented internally (e.g. binary floating-point, 
decimal floating-point, decimal fixed-point, rational) is related to the 
issue of how they are presented externally.  If I see $0.33 does that 
mean 1/3 of a dollar or 33/100 of a dollar?  Does $0.33 * 3 = $0.99 or 
$1.00 (or $1.00000000000000023)?

Python's Decimal type has some nice features that Lisp rationals lack, 
like a default printed representation that people are generally more 
used to seeing and automatic tracking of significant figures (0.1 and 
0.1000 are distinct).

Still, Decimal seems better than rationals for processing monetary 
transactions because a) no additional effort is required on the part of 
the programmer to output a Decimal in the expected format and b) it does 
not hide questionable mathematical operations on monetary quantities, 
like dividing $1.00 by 3.

rg
From: Frode Vatvedt Fjeld
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <2hodpy89tc.fsf@vserver.cs.uit.no>
Ron Garret <·········@flownet.com> writes:

> Still, Decimal seems better than rationals for processing monetary
> transactions because a) no additional effort is required on the part
> of the programmer to output a Decimal in the expected format and b)
> it does not hide questionable mathematical operations on monetary
> quantities, like dividing $1.00 by 3.

Now I am curious, what is $1.00 divided by 3 in this "decimal" system?

-- 
Frode Vatvedt Fjeld
From: Ron Garret
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <rNOSPAMon-78C118.15393020122006@news.gha.chartermi.net>
In article <··············@vserver.cs.uit.no>,
 Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > Still, Decimal seems better than rationals for processing monetary
> > transactions because a) no additional effort is required on the part
> > of the programmer to output a Decimal in the expected format and b)
> > it does not hide questionable mathematical operations on monetary
> > quantities, like dividing $1.00 by 3.
> 
> Now I am curious, what is $1.00 divided by 3 in this "decimal" system?

Well, that's the point.  It's not really well defined.  But in Python 
this is more evident than in Lisp:

? (format t "~$" 1/4)
0.25
NIL
? (format t "~$" 1/2)
0.50
NIL
? (format t "~$" 1/3)
0.33
NIL
? 

versus:

>>> import decimal
>>> D=decimal.Decimal
>>> D('1.00')/D('4')
Decimal("0.25")
>>> D('1.00')/D('2')
Decimal("0.50")
>>> D('1.00')/D('3')
Decimal("0.3333333333333333333333333333")


Lisp covers up the fact that there is something funky going on under the 
hood.  Python doesn't.

rg
From: Kirk  Sluder
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <kirk-251DC4.19332220122006@newsclstr02.news.prodigy.com>
In article 
<·······························@news.gha.chartermi.net>,
 Ron Garret <·········@flownet.com> wrote:

> ? (format t "~$" 1/3)
> 0.33
> NIL
> ? 
> 
> versus:
....
> 
> >>> D('1.00')/D('3')
> Decimal("0.3333333333333333333333333333")
> 
> 
> Lisp covers up the fact that there is something funky going on under the 
> hood.  Python doesn't.


Woah, danger! Mixing up internal representation with external 
printing functions there.  The format macro is similar to the print 
... % expression.  You can do the same cover up with python print 
statements:

>>> foo = 1.00 / 3.00
>>> foo
0.33333333333333331
>>> print "%.20f" % foo
0.33333333333333331483
>>> print "%.2f" % foo
0.33

(Turns out, I don't have python 2.4.)  

Lisp's 1/3 is a ratio with a numerator and denominator, and will be 
represented as such internally until you need to convert it to a 
float. Python decimals are fixed-precision floats. Both ratios and 
decimals appear to have their own library of helper functions for 
wrestling with their unique properties.

I wouldn't mind a decimal package for lisp, but as a text-processing 
monkey, it's not a high-priority itch for me. 

> 
> rg
From: Frode Vatvedt Fjeld
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <2hejqt7xc0.fsf@vserver.cs.uit.no>
Frode Vatvedt Fjeld <······@cs.uit.no> wrote:

>> Now I am curious, what is $1.00 divided by 3 in this "decimal"
>> system?

Ron Garret <·········@flownet.com> writes:

> Well, that's the point.  It's not really well defined.

In that case, this "decimal" numeric system is not for me. 

> But in Python this is more evident than in Lisp:

But there is no "decimal" system in Lisp, so I don't understand this
statement.

> ? (format t "~$" 1/4)
> 0.25
> NIL
> ? (format t "~$" 1/2)
> 0.50
> NIL
> ? (format t "~$" 1/3)
> 0.33
> NIL
> ? 
> 
> versus:
> 
> >>> import decimal
> >>> D=decimal.Decimal
> >>> D('1.00')/D('4')
> Decimal("0.25")
> >>> D('1.00')/D('2')
> Decimal("0.50")
> >>> D('1.00')/D('3')
> Decimal("0.3333333333333333333333333333")
> 
> 
> Lisp covers up the fact that there is something funky going on under
> the hood.  Python doesn't.

What on earth "funky" is going on here except that Python displays yet
another broken numeric system? (Something which really surprises me,
as it was my impression that Python was moving steadily to fix its
original and completely broken numerics.) Division by 3 is not
something I would call funky. You are asking Lisp to format 1/3
according to rules suitable for dollar amounts (rules which, btw, are
specified and standardized in great detail). That's what it
does. Nothing funky goes on, and most certainly nothing is unduely
covered up.

You are also clearly comparing apples and oranges, as in the Lisp
version you are explicitly formatting ("presenting", if you will) the
value, whereas the Python version is showing an unformatted value
(well, it is formatted in some sense, but my meaning should be
evident).

Some brief experimentation with Python's decimal package:

>>> (D('1')/D('3'))*D(10000000000000000000000000000)
Decimal("3333333333333333333333333333")

So again, clearly this system is not for me. But, astonishingly, it
gets worse still:

>>> D("10000000000000000000000000000")/D("3") 
Decimal("3333333333333333333333333333")

>>> D("10000000000000000000000000000.00")/D("3")
Decimal("3333333333333333333333333333")


Now, hopefully there are some buttons and levers in the decimal
package that one can twist and pull to get reasonable behavior. But
this is the behavior you get out of the box.

-- 
Frode Vatvedt Fjeld
From: Thomas A. Russ
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <ymivek3hj69.fsf@sevak.isi.edu>
Ron Garret <·········@flownet.com> writes:

> In article <··············@vserver.cs.uit.no>,
>  Frode Vatvedt Fjeld <······@cs.uit.no> wrote:
> 
> > Ron Garret <·········@flownet.com> writes:
> > 
> > > Still, Decimal seems better than rationals for processing monetary
> > > transactions because a) no additional effort is required on the part
> > > of the programmer to output a Decimal in the expected format and b)
> > > it does not hide questionable mathematical operations on monetary
> > > quantities, like dividing $1.00 by 3.
> > 
> > Now I am curious, what is $1.00 divided by 3 in this "decimal" system?
> 
> Well, that's the point.  It's not really well defined.  But in Python 
> this is more evident than in Lisp:
> 
> ? (format t "~$" 1/4)
> 0.25
> NIL
> ? (format t "~$" 1/2)
> 0.50
> NIL
> ? (format t "~$" 1/3)
> 0.33
> NIL
> ? 
> 
> versus:
> 
> >>> import decimal
> >>> D=decimal.Decimal
> >>> D('1.00')/D('4')
> Decimal("0.25")
> >>> D('1.00')/D('2')
> Decimal("0.50")
> >>> D('1.00')/D('3')
> Decimal("0.3333333333333333333333333333")
> 
> 
> Lisp covers up the fact that there is something funky going on under the 
> hood.  Python doesn't.

What?

You are comparing apples and oranges.

In the Lisp case, you are looking at the formatted output, where you
have implicitly told the formatter that you only want to look at two
decimal places.

Although there is no decimal arithmetic class in CommonLisp, you don't
get any coverup if you try to do the conversion explicitly.  But you
won't even hit the issue unless you ask Lisp to convert something from
rational to floating point.

1/3 in CommonLisp is exactly 1/3 without any limitations imposed by
limited decimal length.  In Python, it appears that there is a limit to
the decimal representation.

Consider the following (in ACL):

  (coerce 1/3 'double-float)  =>  0.3333333333333333d0
  (coerce 1/3 'single-float)  =>  0.33333334


Now, it would be nice if the emerging IEEE decimal floating point
standard would begin to be adopted.  If enough programming languages
embrace it, there may eventually even be dedicated hardware support.

Now entering fantasy land:

But in the meantime, it would probably be a nice feature if the default
"real" number representation of programming languages were a base 10
floating point number instead of base 2.  (In other words, IEEE 854
instead of IEEE 754).  Most computations that involve money aren't
repeated that often in any application (unlike scientific computing),
and for the cases where speed is more important, one could choose to use
base 2 floats.  But it should be slightly more difficult to invoke.
That will probably be a good design choice.

Similarly, it would be good if unlimited precision integers were the
default representation for things like "int" in languages like C++ and
Java, with the current types being renamed more evocatively into
something like intmod32 or something that suggests their limited range
and wrap-around behavior.  Might as well make them unsigned, too, while
we're at it. ;)

Ref: <http://ieeexplore.ieee.org/iel1/2502/1121/00027840.pdf>

-- 
Thomas A. Russ,  USC/Information Sciences Institute
 
From: Marc Battyani
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <OrCdnZWW17QpIxTYnZ2dnUVZ8s-qnZ2d@giganews.com>
"Frode Vatvedt Fjeld" <······@cs.uit.no> wrote
> Ron Garret <·········@flownet.com> writes:
>
>> Still, Decimal seems better than rationals for processing monetary
>> transactions because a) no additional effort is required on the part
>> of the programmer to output a Decimal in the expected format and b)
>> it does not hide questionable mathematical operations on monetary
>> quantities, like dividing $1.00 by 3.
>
> Now I am curious, what is $1.00 divided by 3 in this "decimal" system?

0.1?  ;-)

Marc
From: Marc Battyani
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <D4OdnamintWFXxTYnZ2dnUVZ8qKvnZ2d@giganews.com>
"Marc Battyani" <·············@fractalconcept.com> wrote in message 
·····································@giganews.com...
>
> "Frode Vatvedt Fjeld" <······@cs.uit.no> wrote
>> Ron Garret <·········@flownet.com> writes:
>>
>>> Still, Decimal seems better than rationals for processing monetary
>>> transactions because a) no additional effort is required on the part
>>> of the programmer to output a Decimal in the expected format and b)
>>> it does not hide questionable mathematical operations on monetary
>>> quantities, like dividing $1.00 by 3.
>>
>> Now I am curious, what is $1.00 divided by 3 in this "decimal" system?
>
> 0.1?  ;-)

Hum sorry, this should have been 0.1 euros...
(the euros sign got lost in translation thus ruining an already lame 
joke...)

Marc
From: Damien Kick
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <Vxnih.1663$pQ3.489@newsread4.news.pas.earthlink.net>
Marc Battyani wrote:
> "Frode Vatvedt Fjeld" <······@cs.uit.no> wrote:
> 
>> Now I am curious, what is $1.00 divided by 3 in this "decimal" system?
> 
> 0.1?  ;-)

There is no such thing as 0.1 of a dollar <http://tinyurl.com/yam2hg>.
From: George Neuner
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <ba7ko2ttcv6buc2lhq3imum4vggbt2ee5i@4ax.com>
On Thu, 21 Dec 2006 03:52:21 GMT, Damien Kick <·····@earthlink.net>
wrote:

>Marc Battyani wrote:
>> "Frode Vatvedt Fjeld" <······@cs.uit.no> wrote:
>> 
>>> Now I am curious, what is $1.00 divided by 3 in this "decimal" system?
>> 
>> 0.1?  ;-)
>
>There is no such thing as 0.1 of a dollar <http://tinyurl.com/yam2hg>.

It's called a "dime".

--
for email reply remove "/" from address
From: Thomas A. Russ
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <ymiac1gj21j.fsf@sevak.isi.edu>
Damien Kick <·····@earthlink.net> writes:

> There is no such thing as 0.1 of a dollar <http://tinyurl.com/yam2hg>.

Odd.  I found one:  <http://tinyurl.com/yybozd>

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-018@Yahoo.Com>
> From: Ron Garret <·········@flownet.com>
> Decimal seems better than rationals for processing monetary
> transactions because a) no additional effort is required on the
> part of the programmer to output a Decimal in the expected format
> and b) it does not hide questionable mathematical operations on
> monetary quantities, like dividing $1.00 by 3.

It is not possible to express the result of that division exactly
in decimal notation, so the only *correct* thing to do is to throw
an exception, same as when you try to take sqrt of 2 in rationals,
or sqrt of -1 in reals, or 22/7 in integers. Does it in fact throw
an exception in the implementation of decimal type that you're
familiar with and boasting about?

You didn't mention interval results (upper and lower bounds), so I
assume that Decimal package doesn't do it. With interval decimal
arithmetic then you *can* divide $1.00 by 3, getting the range
$0.33 to $0.34, instead of throwing an exception. The result can
then be printed $0.3[3..4], or as an animated GIF that shows $0.3#
where the # keeps flashing back and forth between 3 and 4, maybe
even spending 2/3 of its time at 3 and 1/3 of its time at 4.
Does your favorite Decimal package do that??
From: ······@gmail.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166783757.330048.126120@a3g2000cwd.googlegroups.com>
So... In the end, what is the current recommended way to do monetary
calculations in Lisp?
From: Pascal Bourguignon
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <873b782khe.fsf@thalassa.informatimago.com>
······@gmail.com writes:
> So... In the end, what is the current recommended way to do monetary
> calculations in Lisp?

Do them in cents instead of dollars or euros.

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

"Specifications are for the weak and timid!"
From: Tim Bradshaw
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166695809.152729.74000@73g2000cwn.googlegroups.com>
Frode Vatvedt Fjeld wrote:

>
> Why would you want a decimal type if you already have rationals? (I'm
> not being rhetorical here.)

In real life, as opposed to whatever half-world programmers live in (we
call it `the soap-pot queue' here) I suspect the answer is because a
lot of calculations are financial calculations which have very
well-defined rounding rules which are probably easier to implement with
fixed-precision decimal representations than fully-fledged rationals.
And, erm, there's a lot of money in those calculations.

(It seems absurd that it matters that much - who really cares if your
VAT is off by a penny because of some rounding issue?  But I think it
does matter both because it makes it easier to check if the answers are
equal not just equal-to-a-suitable-approximation, and because various
kinds of fraud involve moving small amounts of money from large numbers
of places.)
From: Greg Menke
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <m3hcvpju7r.fsf@athena.pienet>
"Tim Bradshaw" <··········@tfeb.org> writes:

> Frode Vatvedt Fjeld wrote:
> 
> >
> > Why would you want a decimal type if you already have rationals? (I'm
> > not being rhetorical here.)
> 
> In real life, as opposed to whatever half-world programmers live in (we
> call it `the soap-pot queue' here) I suspect the answer is because a
> lot of calculations are financial calculations which have very
> well-defined rounding rules which are probably easier to implement with
> fixed-precision decimal representations than fully-fledged rationals.
> And, erm, there's a lot of money in those calculations.

This is where Cobol really shows its value.  The rest of the language is
in large part tedious beyond description, but if I were working on
big-time finanical apps again I'd rather use it than most any other
language out there I've seen.

 
> (It seems absurd that it matters that much - who really cares if your
> VAT is off by a penny because of some rounding issue?  But I think it
> does matter both because it makes it easier to check if the answers are
> equal not just equal-to-a-suitable-approximation, and because various
> kinds of fraud involve moving small amounts of money from large numbers
> of places.)

The off-by-a-penny problem is simplest and most easily communicated
manifestation of rounding issues.  In effect, the problem is
uncontrolled rounding and is critically important in the arithmetic that
eventually produces the off-by-one outputs.  Rounding errors in those
calculations can have a much bigger and hard to predict impact.  You
can't just cover up the problem by a rounding kludge at the end because
what you're effectively doing is adding or removing money by "magic" to
make the numbers look right, which rapidly erodes the integrity of the
accounting process.  And it makes auditing a disaster, "OK, Mr. Auditor,
here if the result is within .02 of our expected value, we adjust to the
expected value." which then leads to you answering to the prosecutor,
"No, we never evaluated the cumulative impact of the error adjustments."

Or another way, if the end results are off by a penny, then your
intermediate terms in the arithmetic that produces them could easily be
off by hundreds and thousands of dollars and thats a lot harder to
accept.

Gregm
From: ············@gmail.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166716788.991218.40070@n67g2000cwd.googlegroups.com>
Greg Menke wrote:

> The off-by-a-penny problem is simplest and most easily communicated
> manifestation of ...

Richard Pryor buying a Ferrari on a programmer's salary and then
getting caught up in a wacky plot to off Superman.
From: ············@gmail.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166776132.408127.36840@a3g2000cwd.googlegroups.com>
Tim Bradshaw wrote:
> (It seems absurd that it matters that much - who really cares if your
> VAT is off by a penny because of some rounding issue?  But I think it
> does matter both because it makes it easier to check if the answers are
> equal not just equal-to-a-suitable-approximation, and because various
> kinds of fraud involve moving small amounts of money from large numbers
> of places.)

Actually non-decimal rounding of financial calculations is a huge deal;
sometime in the 80's (?) a Canadian stock exchange (Toronto?), when it
just started up, saw its index go down and down and down, despite the
stocks themselves doing very well.  This is obviously embarrassing for
a stock exchange ;P  The problem was traced to poor rounding; fixing
the rounding problem corrected the stock index.

mfh
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-013@Yahoo.Com>
> From: Frode Vatvedt Fjeld <······@cs.uit.no>
> What I suspect is that most people who write e.g. "1.02" really
> want the object 102/100. So implementations should support
> *read-default-float-format* RATIONAL.

Are we talking about software programmers who would like to write a
literal "1.02" in source code and have that go in as 102/100
instead of as the nearest floating-point value which happens to
exactly equal 2139095/2097152? Or are we talking about users of
applications who enter 1.02 into a form and want exactly 102/100
For the latter, all we really need is PARSE-RATIONAL which takes
the string typed in the form field and converts it directly to an
exact rational. Such a regular user wouldn't be typing in
s-expressions which require the full recursive algorithm for READ
which parses nested expressions of arbitrary depth. Just parsing a
single string as a rational is quite sufficient.

Now for the former, A programmer who wants to just type 1.02 as a
literal, if PARSE-RATIONAL is already available, then it's only a
slight nuisance for the programmer to have to say
 (PARSE-RATIONAL "1.02")
any place he wants an exact rational like that in his program.
It seems to me better to do that explicitly where needed, rather
than set a global mode that affects the way READ works.
But I suppose if you have a program with a large number of such
exact decimal-fraction values as literals it would be a conveniece
to have a global READ mode, so I'm not rejecting your proposal.
And of course even with neither PARSE-RATIONAL nor the READ mode
available, there's nothing stopping the programmer from saying
 (/ 102 (EXPT 10 2)) ;1.02

> Conversely it would be nice to have something like
> *print-pretty-ratio-format* "~,3F".

You mean print out the exact rational number, or what?
Most times the user wants a decimal-fraction as output, and it
seems to me that if there is no exact decimal fraction for the
correctly-computed rational value then interval notation should be
shown to the user. For example:
* (/ (parse-rational "1.02") (parse-rational "4.7"))
51/235
* (format t "~a~%" (format-interval * 10))
0.217021276[5..6]
* (format t "~a~%" (format-interval ** 30))
0.21702127659574468085106382978[7..8]
From: Andrew Reilly
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <4usbo1F19ng9pU1@mid.individual.net>
On Wed, 20 Dec 2006 03:01:33 -0500, Ken Tilton wrote:

> OK, right up front: you pointy-head intellectual language geniuses can
> spare me the floating-point lecture cr*p. I am a simple application
> programmer and I need seven point frickin two*.

You'll be happy to hear about the current IEEE standardization exercise to
extend the floating point arithmetic standard to include decimal floating
point.  Then you'll get to wonder why the 7.2 that you get as a result is
*different* from the 7.20 that you'd get if you had multiplied 2.4 by 3.0.

You do deserve the floating point lecture, though.  You're getting upset
about the computer making an error of about one in three million, which is
orders of magnitude smaller than the precision of your input values. 
That's why the lisp community refer to that type of maths as "inexact".

If you want decimal arithmetic, it's been available in COBOL, Rexx and
PL/1 for years, and it's available in Java as of a few years ago.  Lisp
has rationals, though, which are arguably much better.  Wouldn't be hard
to add a decimal arithmetic class if anyone cared to.

Doing things in decimal doesn't make them more "right", though.  In fact
it usually makes things slightly worse, in terms of precision, for any
kind of scientific computing.  The accountants can keep it.

-- 
Andrew
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <6b7ih.593$3o1.12@newsfe10.lga>
Andrew Reilly wrote:
> On Wed, 20 Dec 2006 03:01:33 -0500, Ken Tilton wrote:
> 
> 
>>OK, right up front: you pointy-head intellectual language geniuses can
>>spare me the floating-point lecture cr*p. I am a simple application
>>programmer and I need seven point frickin two*.
> 
> 
> You'll be happy to hear about the current IEEE standardization exercise to
> extend the floating point arithmetic standard to include decimal floating
> point.  Then you'll get to wonder why the 7.2 that you get as a result is
> *different* from the 7.20 that you'd get if you had multiplied 2.4 by 3.0.

Why would I wonder? Looks like long multiplication to me. I think you 
missed that I am doing an educational app.

> 
> You do deserve the floating point lecture, though.  You're getting upset
> about the computer making an error of about one in three million, which is
> orders of magnitude smaller than the precision of your input values. 

Now I am sure you missed that I am doing an educatinal app.

> That's why the lisp community refer to that type of maths as "inexact".
> 
> If you want decimal arithmetic, it's been available in COBOL...

Really? What's the syntax? Something inscrutable like comp-3? So much 
for english-like.

> , Rexx and
> PL/1 for years, and it's available in Java as of a few years ago.  Lisp
> has rationals, though, which are arguably much better.  Wouldn't be hard
> to add a decimal arithmetic class if anyone cared to.
> 
> Doing things in decimal doesn't make them more "right", though.  In fact
> it usually makes things slightly worse, in terms of precision, for any
> kind of scientific computing.  The accountants can keep it.
> 

:)

ken

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Tim Bradshaw
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166611615.908126.134870@73g2000cwn.googlegroups.com>
Ken Tilton wrote:

> Why would I wonder? Looks like long multiplication to me. I think you
> missed that I am doing an educational app.

Curiously, I just recently spent some time explaining to someone at
school just why you should never resort to numbers until the last
minute for just these reasons.  Rather than working out 2.4/3 and then
plugging that answer into whatever later stage, keep it as 2.4/3, and
build up some big symbolic expression which you then simplify in one go
at the end.  You get less errors that way in general (on a calculator,
here).

--tim
From: ·····@yahoo.com
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166648262.736452.9770@48g2000cwx.googlegroups.com>
Andrew Reilly wrote:
> On Wed, 20 Dec 2006 03:01:33 -0500, Ken Tilton wrote:
>
> > OK, right up front: you pointy-head intellectual language geniuses can
> > spare me the floating-point lecture cr*p.
>
> You'll be happy to hear about the current IEEE standardization exercise to
> extend the floating point arithmetic standard to include decimal floating
> point.

would that be IEEE-754's lesser known -854 cousin ?

http://en.wikipedia.org/wiki/Ieee_float



> If you want decimal arithmetic, it's been available in COBOL,

trying to burn our brains with memories of PICTURE clauses?

http://www.csis.ul.ie/COBOL/Course/DataDeclaration.htm#part2


But performance for BSD & String instructions is de-empasised
with implementing in x86 CISC on RISC cores...

although we are finally getting (IBM mainframe "VM microcode assist" /
PRISM)

http://en.wikipedia.org/wiki/Virtualization_Technology#Hardware_support

---

We are asking Kenny to be rational?
From: Joe Marshall
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166657019.410417.180540@79g2000cws.googlegroups.com>
·····@yahoo.com wrote:
>
> We are asking Kenny to be rational?

The alternative is getting him fixed (-point).
From: William D Clinger
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1166892054.722953.44880@48g2000cwx.googlegroups.com>
Joe Marshall wrote:
> ·····@yahoo.com wrote:
> >
> > We are asking Kenny to be rational?
>
> The alternative is getting him fixed (-point).

Perfect summary of the whole thread.  Well done, guys.

Will
From: Andrew Reilly
Subject: Re: (* 2.4 3) => 7.2000003 WTF?! Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <4utur6F19or1qU2@mid.individual.net>
On Wed, 20 Dec 2006 12:57:42 -0800, n2kra wrote:

> Andrew Reilly wrote:
>> On Wed, 20 Dec 2006 03:01:33 -0500, Ken Tilton wrote:
>>
>> > OK, right up front: you pointy-head intellectual language geniuses can
>> > spare me the floating-point lecture cr*p.
>>
>> You'll be happy to hear about the current IEEE standardization exercise to
>> extend the floating point arithmetic standard to include decimal floating
>> point.
> 
> would that be IEEE-754's lesser known -854 cousin ?
> 
> http://en.wikipedia.org/wiki/Ieee_float

Yes, I think that's probably the one.  An IBM fellow named Mike Cowlishaw
(?sp?) has been making some noise about it over in comp.arch.arithmetic.

>> If you want decimal arithmetic, it's been available in COBOL,
> 
> trying to burn our brains with memories of PICTURE clauses?
> 
> http://www.csis.ul.ie/COBOL/Course/DataDeclaration.htm#part2
> 
> 
> But performance for BSD & String instructions is de-empasised with
> implementing in x86 CISC on RISC cores...

I've yet to find *any* plausible example where decimal arithmetic
performance is conceivably the bottleneck.  Doing it in software is the
right way to spend transistors.  IMO.  YMMV.

> although we are finally getting (IBM mainframe "VM microcode assist" /
> PRISM)
> 
> http://en.wikipedia.org/wiki/Virtualization_Technology#Hardware_support
> 
> ---
> 
> We are asking Kenny to be rational?

We could compensate by using floating point in base-e.  That'd be optimal
in a number of ways, if we could figure out how to represent it...

Cheers,

-- 
Andrew
From: John Thingstad
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <op.tkumsuripqzri1@pandora.upc.no>
On Wed, 20 Dec 2006 09:01:33 +0100, Ken Tilton <·········@gmail.com> wrote:

> OK, right up front: you pointy-head intellectual language geniuses can  
> spare me the floating-point lecture cr*p. I am a simple application  
> programmer and I need seven point frickin two*.
>
> To start with, let's take some arbitrary Lisp garbage like 7.2000003 and  
>   just count the meaningful decimal places, in this case (and in the  
> case of 7.19999997) just one. Think about it. You see that garbage, you  
> know what is going on: 3.14799999999? Easy: 3.148. Why can't Lisp***  
> figure that out?! <sigh>
>

Because the computer sees the number in binary, not decimal.
I wrote a graph module once where I had to deal with this.
I created a class dynamic-ruler to deal with this.
(It's in C++ so it's of no direct interest here.)
The idea is to figure out the right exponent first. Then read off the
nearest value by looking a a ruler.


-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Ken Tilton
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <Tu6ih.591$3o1.534@newsfe10.lga>
John Thingstad wrote:
> On Wed, 20 Dec 2006 09:01:33 +0100, Ken Tilton <·········@gmail.com> wrote:
> 
>> OK, right up front: you pointy-head intellectual language geniuses 
>> can  spare me the floating-point lecture cr*p. I am a simple 
>> application  programmer and I need seven point frickin two*.
>>
>> To start with, let's take some arbitrary Lisp garbage like 7.2000003 
>> and    just count the meaningful decimal places, in this case (and in 
>> the  case of 7.19999997) just one. Think about it. You see that 
>> garbage, you  know what is going on: 3.14799999999? Easy: 3.148. Why 
>> can't Lisp***  figure that out?! <sigh>
>>
> 
> Because the computer sees the number in binary, not decimal.

You got the ***! :)

kt

-- 
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: =?ISO-8859-15?Q?Andr=E9_Thieme?=
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <embe37$vlf$1@registered.motzarella.org>
(float (* 24/10 3)) => 7.2

(defconstant +pi+ 
3141592653589793238462643383279/1000000000000000000000000000000)
From: Debian User
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <458a87d9$0$14820$dbd41001@news.wanadoo.nl>
As I understand, the newer gcc versions also support decimal
artithmetic.
From: Frank Buss
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <1ool6nmydv060.1f5s2vzay4k9r$.dlg@40tude.net>
Ken Tilton wrote:

> Be careful: 3.1234509 is pretty close to 3.12345 absolutely speaking, 
> but that is not the kind of garbage produced by Lisp floating-point 
> errors. And for god's sake make sure your code works on negative values 
> as well as positive.

I'm most of the time only an application programmer, too, but I think the
interesting point is the number of significant digits. It's a bit
difficult, because this varies with the number and depends on float-radix,
too (I'm sure some pointy-head intellectual language geniuses can explain
this in more detail), but if your Lisp implementation has at least standard
C-float values, it's safe to use 6 decimal places to simulate calculator
behaviour:


(defun nice-round (number &optional (places 6))
  (let ((size (expt 10 places)))
    (float (/ (round (* number size)) size))))


If you want this in your repl, too, try this:


(defvar *original-pprint-dispatch* *print-pprint-dispatch*)
(defparameter *kens-print-pprint-dispatch* (copy-pprint-dispatch))

(set-pprint-dispatch 
 'float
 (lambda (stream float)
   (let ((*print-pprint-dispatch* *original-pprint-dispatch*))
     (format stream "~a" (nice-round float))))
 0 *kens-print-pprint-dispatch*)

(setf *print-pprint-dispatch* *kens-print-pprint-dispatch*)
(setf *print-pretty* t)


Now you can enter (* -2.4 3) and Lisp says -7.2.

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Robert Maas, see http://tinyurl.com/uh3t
Subject: Re: (* 2.4 3) => 7.2000003 WTF?!  Let's Fix Lisp! Noob Programming Challenge
Date: 
Message-ID: <REM-2006dec24-012@Yahoo.Com>
> From: Ken Tilton <·········@gmail.com>
> I am a simple application programmer and I need seven point
> frickin two*.

Then don't use frickin floating point!! Floating point was never
designed to give exact results of calculations. If you want exact
calculations, use rational numbers, which are provided in Common
Lisp for your enjoyment.

CMU Common Lisp 18b
* 24/10
12/5
* 3
3
* (* ** *)
36/5
* (format t "~39,35f~%" *)
  7.20000000000000000000000000000000000
;Is that accurate enough for your pleasure?
* (format t "~a~%" (string-right-trim "0" (format nil "~39,35f" **)))
  7.2
;Is that clean enough for your pleasure?

Only a fool uses a hammar instead of a screwdriver and expects the
screw to rotate instead of slam directly into the wood.
In the future, please pick the appropriate tool for your purpose.

> let's take some arbitrary Lisp garbage like 7.2000003 and just
> count the meaningful decimal places

Given that you've specifically asked Lisp to perform approximate
floating-point calculations instead of exact rational calculations,
you've asked Lisp to compute a wrong answer that is "close" to the
correct answer. At that point, there's no way to reconstruct the
correct answer because you don't have enough information any more.
If you think that seeing 7.2000003 always means the exact correct
answer is 7.2, you're a fool.

> You see that garbage, you know what is going on: 3.14799999999?
> Easy: 3.148.

Nope, that's not a valid conclusion. There isn't enough information
to know what the correct answer is. You're just guessing that the
correct value is 3.148.

> Why can't Lisp*** figure that out?!

Because there isn't enough information to know that.
Consider this example:
* (sqrt (sqrt 3111700))
42.00001
Would you claim the exactly correct answer is 42, and Lisp should
figure that out and print that?

> To be safe, we want a maximum number of places in case some yobbo
> passes in pi or (/ 1 3).

There's no maximum number of places to either. No matter how many
places somebody calculates for either, it's always possible to
calculate more places. You're seriously sounding like a troll now.

> And where we start with a computation**, we can /tell/ the
> function exactly the maximum by adding the decimal places of each
> multiplicand.

There's only multiplicand, and one multiplier, in a traditional
two-operand multiplication task. Perhaps you forgot that in your
haste to post a trolling message?

So would you like some sort of interval arithmetic package that
started off with upper and lower bounds on each input value and
then calculated worst-case upper and lower bounds on each
intermediate result, and then presented the final result in
interval notation? How many significant digits should be used for
intermediate results when there are n significant digits for each
original input value? What if some original input values have more
significant digits than others? Please specify precisely what you
want an interval arithmetic package to do in this regard.

> make sure your code works on negative values as well as positive.

Don't worry about that. I'm not as stupid as you are. I wouldn't
overlook any obvious case like that.