[plt-scheme] Numerical precision

From: Joe Marshall (jmarshall at alum.mit.edu)
Date: Thu Mar 12 13:31:32 EDT 2009

>> On Mar 11, 2009, at 3:29 PM, Joe Marshall wrote:
>>
>>> You have defined something weird here.  Your arithmetic is no
>>> longer associative where you might expect it to be.

On Wed, Mar 11, 2009 at 1:46 PM, Jaime Vargas <jev at mac.com> wrote:
> I see your point, the arithmetic is not associative.
> Can you point me to a better technique?

Unfortunately, no.  The best technique depends a lot on what you are
doing.  If you do all the arithmetic with exact numbers and never round,
then you'll get the `mathematically correct' number.  If you round only
just before printing the answer, you'll get a number that is no more than
1 unit away from the mathematically correct number.

But if you are doing finance, then it is very likely that you are computing
something that someone else may also be computing.  In that case, you
might not want the mathematically correct number, but instead the *same*
number as the other party.  You would have to round your answers at the
same points in the computation as the other person.

So if it were me, I'd probably not try to hide the rounding within the
arithmetic
operations, but make it an explicit operation.  That way, you'll know when
it happens.

Here's a thought.  Define a `round-to' function like this:
(define (round-to p)
 (let* ((exact-p (inexact->exact p))
	(exact-reciprocal-p (/ 1 exact-p)))
   (lambda (x)
     (* exact-p
	(round->exact
	 (* (inexact->exact x)
	    exact-reciprocal-p))))))

Which you can use like this:
  ((round-to 1/10) (+ .3 .7 .2)) => 6/5

But you should be aware of this:
  ((round-to .1) (+ .3 .7 .2)) => 10808639105689191/9007199254740992

Decimal floating point fractions often don't have a binary float equivalent.
Like these:
(inexact->exact .1)
;Value: 3602879701896397/36028797018963968

(inexact->exact .3)
;Value: 5404319552844595/18014398509481984

(inexact->exact .7)
;Value: 3152519739159347/4503599627370496

(inexact->exact .2)
;Value: 3602879701896397/18014398509481984

If you start with decimal fractions, you'll likely end up with odd-looking
results.


-- 
~jrm


Posted on the users mailing list.