From: Barry Margolin on
In article <m18w7qfz65.fsf(a)earthlink.net>,
Raymond Toy <rtoy(a)earthlink.net> wrote:

> How do you know there is a performance tradeoff? Did you check to see
> if sbcl does something different? AFAICT, sbcl does nothing special
> in this case and punts to the generic expt routine which checks the
> types of both arguments to figure out what needs to be done. The cost
> of returning the accurate answer is very small.

But what's the benefit? How often do you use LOG with floating point
parameters where the number is an exact power of the base?

--
Barry Margolin, barmar(a)alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Raymond Toy on
>>>>> "Barry" == Barry Margolin <barmar(a)alum.mit.edu> writes:

Barry> In article <m18w7qfz65.fsf(a)earthlink.net>,
Barry> Raymond Toy <rtoy(a)earthlink.net> wrote:

>> How do you know there is a performance tradeoff? Did you check
>> to see if sbcl does something different? AFAICT, sbcl does
>> nothing special in this case and punts to the generic expt
>> routine which checks the types of both arguments to figure out
>> what needs to be done. The cost of returning the accurate
>> answer is very small.

Barry> But what's the benefit? How often do you use LOG with
Barry> floating point parameters where the number is an exact
Barry> power of the base?

What? The benefit is a more accurate answer. What about this then:

(expt 5 #c(3d0 0d0)) -> #C(125.00001127654393D0 0.0D0)

Would people rather get #c(125d0 0d0) instead?

It's not about the base, it's about implementing (expt x y) as
(exp (* y (log x))). CMUCL does this, but makes x and y have the same
precision before doing the computation. SBCL just uses the formula as
is, with the types as given.

Ray
From: Raymond Toy on
>>>>> "Raymond" == Raymond Toy <rtoy(a)earthlink.net> writes:

>>>>> "Barry" == Barry Margolin <barmar(a)alum.mit.edu> writes:
Barry> In article <m1mxw7fi6p.fsf(a)earthlink.net>,
Barry> Raymond Toy <rtoy(a)earthlink.net> wrote:

>>>
>>> What is the expected answer?
>>>
>>> The same issue applies to (log 10 10d0). Ccl and sbcl return
>>> 1.0000000138867557D0. Cmucl and clisp return 1d0.

Barry> Floating point is an approximation, and errors can creep
Barry> in. It looks like the latter implementations have some
Barry> special checks for when the number is an exact power of the
Barry> base, while the former use the same algorithm for
Barry> everything.

Raymond> Well, the difference is way bigger than I would have
Raymond> expected. In fact, I know that sbcl computes (expt 2
Raymond> #c(2d0 0d0)) as (exp (* #c(2d0 0d0) (log 2))). That (log
Raymond> 2) returns a single-float as expected and required. This
Raymond> is what causes the loss of accuracy.

There's also a kind of inconsistency (with ccl, perhaps others):

(expt 5 #c(3d0 0d0)) -> #c(125.0001127654393d0 0d0)
(expt 5 3d0) -> 125d0

I would have expected the results to be much closer.

Ray
From: Captain Obvious on
Captain>> Well, if you want to work at double accuracy, why don't
Captain>> you explicitly specify 2 as double-float?

RT> Yes, I am well aware of how to get the answer I want. My question is
RT> what is the correct answer?

When you're working with floating point numbers, there is no such thing as
"the correct answer".
You should NEVER compare floating point numbers directly, but only with some
precision threshold which is relevant to your application and calculations
you're doing.

RT> How do you know there is a performance tradeoff?

Let's say I guess so.
Count all possible types for base and power. Mutiply them.
That's a number of cases it has to deal with.
If you deal with parameters one by one, number of cases is a lot smaller --
you still need to handle calculations which are supposed to be precise by
standard in a special way, but for the rest, one common code path will do.

RT> The cost of returning the accurate answer is very small.

If you think that SBCL can be improved, why don't you speak with SBCL
developers?

RT> And who said it was only sbcl that does it this way?

I guess other have same rationale.

But CLISP is high-overhead anyway, so it can spend some time doing dispatch.

RT> The rule of float and rational contagion says the rational is
RT> converted to a float of the same format. This hints that 2 should be
RT> converted to 2d0. The very last sentence says

RT> In the case of complex numbers, the real and imaginary parts
RT> are effectively handled individually.

How about a full quote:

"When rationals and floats are compared by a numerical function, the
function rational is effectively called to convert the float to a rational
and then an exact comparison is performed. In the case of complex numbers,
the real and imaginary parts are effectively handled individually."

They are handled individually only for comparison!

As I understand, complex numbers are considered to be different from
floating numbers and rules of contagion are relaxed for them.

12.1.5.2 Rule of Complex Contagion
"When a real and a complex are both part of a computation, the real is first
converted to a complex by providing an imaginary part of 0."

That's all. Formats are not mentioned at all.

From: Tamas K Papp on
On Tue, 11 May 2010 08:15:05 -0400, Raymond Toy wrote:

>>>>>> "Barry" == Barry Margolin <barmar(a)alum.mit.edu> writes:
>
> Barry> In article <m18w7qfz65.fsf(a)earthlink.net>, Barry> Raymond
> Toy <rtoy(a)earthlink.net> wrote:
>
> >> How do you know there is a performance tradeoff? Did you check
> >> to see if sbcl does something different? AFAICT, sbcl does
> >> nothing special in this case and punts to the generic expt
> >> routine which checks the types of both arguments to figure out
> >> what needs to be done. The cost of returning the accurate answer
> >> is very small.
>
> Barry> But what's the benefit? How often do you use LOG with Barry>
> floating point parameters where the number is an exact Barry> power
> of the base?
>
> What? The benefit is a more accurate answer. What about this then:
>
> (expt 5 #c(3d0 0d0)) -> #C(125.00001127654393D0 0.0D0)
>
> Would people rather get #c(125d0 0d0) instead?
>
> It's not about the base, it's about implementing (expt x y) as (exp (* y
> (log x))). CMUCL does this, but makes x and y have the same precision
> before doing the computation. SBCL just uses the formula as is, with
> the types as given.

I prefer CMUCL's approach. I think that the extra cost, if any,
should be trivial, especially on todays CPU's. I suggest that report it
as a bug in SBCL.

Now the other, completely orthogonal question is whether a numerical
routine should calculate "exact" values for cases when it is possible.
The only case when I don't like that to happen is when it causes a
discontinuity: eg if a routine uses an approximation for non-integers
but an "exact" method for integers, a discontinuity might arise in the
neighborhood of integers. So I prefer if the user can signal which
method to use: eg have (expt 5 3) calculate it the "exact" way, and
(exp 5 3d0) or (exp #C(3d0 0)) using an approximation (which, in the
case of EXP, is so good that it is hard to distinguish from the exact
result). But this might matter for certain implementations of the
gamma function, etc.

In the particular problem, I would prefer if (expt x (complex y 0))
always gave the same result as (expt x y), even if there is some extra
cost/overhead. I care much more about correctness than speed.

Tamas