Re: [Scheme-reports] Definition of expt (was #391 - a selection of error predicates) Mark H Weaver (08 Aug 2012 18:08 UTC)

Re: [Scheme-reports] Definition of expt (was #391 - a selection of error predicates) Mark H Weaver 08 Aug 2012 18:07 UTC

On 08/08/2012 07:55 AM, Alex Shinn wrote:
> On Wed, Aug 8, 2012 at 8:44 PM, Mark H Weaver<mhw@netris.org>  wrote:
>> On 08/08/2012 02:49 AM, Alex Shinn wrote (on the WG1 list):
>>>
>>> These predicates seem random, reflecting only the
>>> historical precedent of what was stated as "signals
>>> an error" vs "is an error".  I'm not even convinced that
>>> distinction was made by design rather than the
>>> stylistic convention of the editors at the time.
>>>
>>> For expt, in particular, we added this note ourselves,
>>> and the actual text is:
>>>
>>>     0.0^z is 1.0 if z = 0.0, and 0.0 if (real-part z) is positive.
>>>     For other cases in which the first argument is zero, either
>>>     an error is signalled or an unspecified number is returned.
>>>
>>> Apart from the wording being a clumsy, saying
>>> an "error is signalled _or_ an unspecified result
>>> is returned" is the same as saying "the result is
>>> an error."
>>
>>
>> The text does not say "or an unspecified result is returned".  It says "or
>> an unspecified _number_ is returned".  Therefore, it is not the same.
>
> Not quite the same, but close enough.
> We should signal an error, or do something
> unspecified, not one or the other.

Given the tendency of the R6RS to specify so much more than other
reports had, I suspect they had good reason to give implementations
leeway here.  Some of the cases are surely controversial, and yet some
implementors may have strong opinions on how they should be handled.

For example, I would argue that some of these cases (e.g. exact zero
raised to any power that's not an exact non-negative integer) ought to
raise an exception, others (e.g. +0.0 ^ -1.0) ought to return +inf.0,
and others (e.g. +0.0 ^ -1.0+1.0i) should return a complex infinity
(which some might represent as +nan.0+nan.0i, but I've recently learned
that C99 and C11 represent as a complex number with one NaN part and one
infinity of unspecified sign, with good reason).

>>> I propose changing the text to:
>>>
>>>     0^z is 1 if z = 0, and 0 if (real-part z) is positive.
>>>     It is an error if (real-part z) is negative.
>>
>>
>> You've made two questionable changes to the meaning of this definition,
>> beyond the description of what happens in the error/unspecified case.
>>
>> 1. The current text uses "0.0" and "1.0" which suggests inexact numbers.
>> You've changed these to exact numbers.   I interpret the current text to
>> apply only when the base is an _inexact_ zero, and to specify inexact
>> results.  I interpret your proposed text as mandating exact return values,
>> and possibly also applying when the base is an exact zero.
>
> This was very much intentional.  The current text
> was a derivation from R5RS that was never voted
> on - I simply fixed it.

Actually, the current text is almost precisely taken from the R6RS, and
while I disagree with many of the choices of the R6RS, they did a very
competent job on numerics for the most part.

> The general rule we've been taking is exact zero
> causes errors, inexact zero returns whatever the
> floating point processor returns.

As far as I know, most (all?) floating-point processors don't do complex
arithmetic directly, or at least not exponentials, so we can't rely on
that rule here.

As Kahan notes in section 10 of "Branch Cuts for Complex Elementary
Functions (or: Much Ado About Nothing's Sign Bit)":

   The function z^w has two different definitions.  One is recursive and
   applicable only when w is an integer:

      z^0 = 1   and   z(w+1) = z^w * z   whenever z^w exists.

   The second definition is analytic:

      z^w := limit as zeta->z of exp(w * ln(zeta)),

   provided that the limit exists using the principal value and domain
   of ln(zeta).  The limit process is necessary to cope smoothly with
   z=0.

More generally, limit processes are the method of choice in IEEE 754
style arithmetic to determine the behavior of functions in the presence
of signed zeroes and infinities.

However, I would strongly argue that limit processes are appropriate
only for inexact arithmetic in Scheme.  More specifically, a limit
process must be used only for inexact inputs, and must produce inexact
outputs.

An exact result must always agree with the precise mathematically
correct result of the function in question.

In this case, if z is an exact zero, then we cannot use the analytic
definition z^w = exp(w * ln(z)) because ln(z) is not defined at zero.
Limit processes are not appropriate for an exact zero input.  Therefore,
here we can rely only on the recursive definition, which applies only
when the exponent is a non-negative integer, and I'd go further and
require that it be exact, but reasonable people might disagree here.

      Mark

_______________________________________________
Scheme-reports mailing list
Scheme-reports@scheme-reports.org
http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports