[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [srfi-70] Limit

This page is part of the web mail archives of SRFI 70 from before July 7th, 2015. The new archives for SRFI 70 contain all messages, not just those from before July 7th, 2015.

>  Function: limit proc z1 z2
>      Proc must be a procedure taking a single inexact argument.
>      z2 should be chosen so that proc is expected to be monotonic or
>      constant on arguments between z1 and z1 + z2.
>      Limit computes the limit of proc as its argument approaches z1
>      from z1 + z2.  Limit returns a complex number or real infinity
>      or `#f'.

This I like a lot better.

> LIMIT was created so that static choices for limit cases like:
>   (expt 0 0)                                    ==> 1
> or
>   (expt 0 0)                                    ==> 0/0
> don't necessitate workarounds when computing with functions like
> (lambda (x) (expt x x)):

>   (limit (lambda (x) (expt x x)) 0 1e-9)        ==> 1/0

Unfortunately, my experience is that this approach is highly unreliable.
In the end, I spent more time doing analytical sanity checks myself than
it took to write the proper numerical code directly after understanding
the limits properly.

Example: An important function from information theory is

        f(x) =  -x log(x).

This function is in principle well behaved (smooth, analytic, etc.) on (0,1],
but its derivative does not exist at x = 0. Moreover, f(0) cannot directly be
computed numerically because the underflow from log(x) is not cancelled by the
multiplication with zero. Practical numerical code: IF x < xmin THEN 0 ELSE x log(x),
where xmin is chosen minimal such that log(xmin) is an ordinary number and
not -infinity.

Using LIMIT in this case is not a good idea for two reasons:
a) It is expensive and unnecessary, except for very small x.
b) At least the reference implementation of LIMIT doesn't get it right:

        (limit (lambda (x) (* -1 x (log x))) 0 1e-9) => -inf.0

This may be a bug in the reference implementation, but it is certainly a
violation of the new specification as f(x) is monotonic on [0,1/e].

When you try to fix the reference implementation, you will find that it
cannot be fixed because it comes from the "black box" procedure:
At a certain moment f(x) becomes -inf.0, so that must be the limit.

I can relate another experience: The Mathematica system has an operation
Limit[], which finds limits symbolically, and a function NLimit[] which finds
limits numerically. Limits[] turns out to be useful sometimes, but it took
many years and many releases until it became something I nearly trust.
NLimits[] on the other hand is tricky, even though it makes an effort to report
when it fails, e.g. NLimit[x Log[x], x -> 0.] => "cannot recognize limit".

Bottom line: In the end, LIMIT might do more harm than it is worth.
You might want to reconsider if it is a feature that is essential for
the Scheme programming language itself.