From: Peter Seibel
Subject: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <m3u14ucsw0.fsf@javamonkey.com>
Is there a deep reason--mathematical, implementational or
otherwise--that numbers of type (complex float) can have a zero
imaginary part while (complex rationals) can not? Or is it just one of
those things?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Kent M Pitman
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <sfwoev2s3u4.fsf@shell01.TheWorld.com>
Peter Seibel <·····@javamonkey.com> writes:

> Is there a deep reason--mathematical, implementational or
> otherwise--that numbers of type (complex float) can have a zero
> imaginary part while (complex rationals) can not? Or is it just one of
> those things?

If I recall from being only peripherally involved in this aspect of
the design, it comes down to issues of exactness/approximateness.  So
rationals are assumed to be more exact, and the fact of realness is
more believable in that case...  (Note that this stands in contrast to
Scheme, where exact/inexact is an orthogonal dimension to
float/integer, so you can have inexact integers and exact floats in
Scheme.)

Numerical analysis is not my strong suit, but my sense is that being
even just a little off of the real plane is really quite important,
and so if 0.0 is the result of round-off and not due to precise
computations that exactly led to zero, that's worrisome and it's worth
not simplifying the result to a float in a way that implies more 
confidence in realness than the error margin will support.

Moroever, and more subtly, maybe also because near misses such as
0.0000001 might be only non-zero due to roundoff error even though the
true and correct answer should have been 0.000000, and therefore
perhaps, it's an apology to those numbers not being reducible that we
don't reduce the ones that have just as much error range but fall in a
coincidentally better place...
From: William D Clinger
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <fb74251e.0311241103.1baf6d57@posting.google.com>
Kent M Pitman wrote:
> (Note that this stands in contrast to
> Scheme, where exact/inexact is an orthogonal dimension to
> float/integer, so you can have inexact integers and exact floats in
> Scheme.)

In Scheme, you can have inexact integers and exact reals, but
Scheme has no "float" type.  In typical implementations of Scheme,
an inexact integer is represented by a flonum, but exact reals are
_not_ represented by flonums.

Will
From: Kent M Pitman
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <wkptfh1plp.fsf@nhplace.com>
··········@verizon.net (William D Clinger) writes:

> Kent M Pitman wrote:
> > (Note that this stands in contrast to
> > Scheme, where exact/inexact is an orthogonal dimension to
> > float/integer, so you can have inexact integers and exact floats in
> > Scheme.)
> 
> In Scheme, you can have inexact integers and exact reals, 

Oops, thanks for the correction.  I knew this but was being sloppy.
However, ...

> but Scheme has no "float" type.

True.  But it is not forbidden from using the float type internally.

> In typical implementations of Scheme, an inexact integer is
> represented by a flonum, but exact reals are _not_ represented by
> flonums.

But is that a requirement of the spec?  I have never assumed it to be.
I've always assumed that a correct implementation of scheme could do

(defstruct scheme-number
  exact-p
  internal-representation)

And then could decide lazily whether to represent something as an exact
real by choosing a float if the result could be represented by the float
without loss of precision.  As such, it seems to me that 

 (/ 1 4) could yield 

 (make-scheme-number :exact-p t :internal-representation 0.25)

with no loss of precision and with no deviation from the spec.
From: Ray Dillinger
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <3FC2BE87.15E8C360@sonic.net>
Kent M Pitman wrote:
> 
> ··········@verizon.net (William D Clinger) writes:
> 
> > Kent M Pitman wrote:
> > > (Note that this stands in contrast to
> > > Scheme, where exact/inexact is an orthogonal dimension to
> > > float/integer, so you can have inexact integers and exact floats in
> > > Scheme.)
> >
> > In Scheme, you can have inexact integers and exact reals,
> 
> Oops, thanks for the correction.  I knew this but was being sloppy.
> However, ...
> 
> > but Scheme has no "float" type.
> 
> True.  But it is not forbidden from using the float type internally.
> 
> > In typical implementations of Scheme, an inexact integer is
> > represented by a flonum, but exact reals are _not_ represented by
> > flonums.
> 
> But is that a requirement of the spec?  I have never assumed it to be.
> I've always assumed that a correct implementation of scheme could do

It is not.  The scheme standard in fact mandates NOTHING about how you
represent your numbers.  In practice, exact non-integral real numbers 
represented in float format is an implementation decision that will make
it hard to comply with the standard, because it will be hard to make 
sure you're not getting roundoff errors, etc, in your operations and
there are a lot of operations (multiplication, division, addition, and 
subtraction for starters) that are supposed to give exact results when 
called with exact arguments. So exact reals are normally represented
as ratios. 

>  (/ 1 4) could yield
> 
>  (make-scheme-number :exact-p t :internal-representation 0.25)
> 
> with no loss of precision and with no deviation from the spec.

Yep, it could.  But when you multiply it by an exact 1/3, you'll 
have to convert it to a ratio so you can get an exact 1/12 as a 
result.

				Bear
From: JP Massar
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <csn4svs0fant5gslvc9rqr6qht3nbkda84@4ax.com>
On Mon, 24 Nov 2003 04:10:19 GMT, Peter Seibel <·····@javamonkey.com>
wrote:

>Is there a deep reason--mathematical, implementational or
>otherwise--that numbers of type (complex float) can have a zero
>imaginary part while (complex rationals) can not? Or is it just one of
>those things?
>
>-Peter

A completely random theory:

For a similar reason that when you use, e.g., 10/20, you get 1/2 ?
Or 5/1 -> 5

Floats never get 'reduced', whereas rationals do.  Applying 'complex'
as a modifier doesn't change that property.
From: Peter Seibel
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <m3y8u59vah.fsf@javamonkey.com>
JP Massar <······@alum.mit.edu> writes:

> On Mon, 24 Nov 2003 04:10:19 GMT, Peter Seibel <·····@javamonkey.com>
> wrote:
> 
> >Is there a deep reason--mathematical, implementational or
> >otherwise--that numbers of type (complex float) can have a zero
> >imaginary part while (complex rationals) can not? Or is it just one of
> >those things?
> >
> >-Peter
> 
> A completely random theory:
> 
> For a similar reason that when you use, e.g., 10/20, you get 1/2 ?
> Or 5/1 -> 5

Actually I was wondering about the other way: I like that 10/20 is
just another way of writing 1/2 and that #c(3 0) is just another way
of writing 3. I was wondering why, given that, #c(3.0 0.0) is a
different object than 3.0.

> Floats never get 'reduced', whereas rationals do. Applying 'complex'
> as a modifier doesn't change that property.

Yeah, but why not?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Nicolas Neuss
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <87k75ny46x.fsf@ortler.iwr.uni-heidelberg.de>
Peter Seibel <·····@javamonkey.com> writes:

> Actually I was wondering about the other way: I like that 10/20 is
> just another way of writing 1/2 and that #c(3 0) is just another way
> of writing 3. I was wondering why, given that, #c(3.0 0.0) is a
> different object than 3.0.
> 
> > Floats never get 'reduced', whereas rationals do. Applying 'complex'
> > as a modifier doesn't change that property.
> 
> Yeah, but why not?

One could argue in the following way: floats represent intervals of
numbers.  And complex numers resulting from computations represent
"intervals" (=rectangles) in the complex plane.  This information is kept
with #c(3.0 0.0).

Nicolas.
From: Joe Marshall
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <brqzlgad.fsf@comcast.net>
Nicolas Neuss <·······@iwr.uni-heidelberg.de> writes:

>
> One could argue in the following way:  floats represent intervals of
> numbers.  

You *could* argue that, but floats are definitely not intervals.

-- 
~jrm
From: Barry Margolin
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <barmar-D3B9AD.15455805122003@netnews.attbi.com>
In article <··············@javamonkey.com>,
 Peter Seibel <·····@javamonkey.com> wrote:

> Actually I was wondering about the other way: I like that 10/20 is
> just another way of writing 1/2 and that #c(3 0) is just another way
> of writing 3. I was wondering why, given that, #c(3.0 0.0) is a
> different object than 3.0.

Because if the 0.0 is the result of a computation, it's likely to be an 
approximation to zero, not exact.

Another reason that I don't think anyone has touched on is simple 
efficiency.  All computers operate very efficiently on fixnums, so if 
you can reduce a complex to an equivalent fixnum, there should be a 
significant performance boost, and this will maximized if the reduction 
takes place once when the value is created, rather than every time it's 
processed.

While it's true that most computers also have hardware support for 
floating point, they're still not nearly as fast as integers.  So the 
impact of reducing once will probably not be as significant.

-- 
Barry Margolin, ······@alum.mit.edu
Woburn, MA
From: Kaz Kylheku
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <cf333042.0312060112.da165c0@posting.google.com>
Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@javamonkey.com>...
> JP Massar <······@alum.mit.edu> writes:
> 
> > On Mon, 24 Nov 2003 04:10:19 GMT, Peter Seibel <·····@javamonkey.com>
> > wrote:
> > 
> > >Is there a deep reason--mathematical, implementational or
> > >otherwise--that numbers of type (complex float) can have a zero
> > >imaginary part while (complex rationals) can not? Or is it just one of
> > >those things?
> > >
> > >-Peter
> > 
> > A completely random theory:
> > 
> > For a similar reason that when you use, e.g., 10/20, you get 1/2 ?
> > Or 5/1 -> 5
> 
> Actually I was wondering about the other way: I like that 10/20 is
> just another way of writing 1/2 and that #c(3 0) is just another way
> of writing 3. I was wondering why, given that, #c(3.0 0.0) is a
> different object than 3.0.

But the object #c(3.0 0) is 3.0. So if #c(3.0 0.0) were *also* 3.0,
the conclusion would be that 0.0 and 0 are the same.

So one way of looking at it is that 0.0 and 0 are not the same object,
and everything follows from that. So if there is any controversy, it
should be focused on 0.0 versus 0.

It's good to treat 0.0 as distinct from 0 because it is an inexact
number. Some numerical computation can put out 0.0 when the abstract
theory behind that computation says that the true answer is
0.0000000000000000001.

Only the mathematical context of the problem can determine whether
small floats like 0.0 or 1.0 exactly represent their integer
counterparts or whether they are approximations. When it comes to
assigning a type to 0.0, it's better that the machine consistently
follows a safe rule which does not promise too much about the accuracy
of that number.
From: Peter Seibel
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <m33cbxu6oa.fsf@javamonkey.com>
···@ashi.footprints.net (Kaz Kylheku) writes:

> Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@javamonkey.com>...
> > JP Massar <······@alum.mit.edu> writes:
> > 
> > > On Mon, 24 Nov 2003 04:10:19 GMT, Peter Seibel <·····@javamonkey.com>
> > > wrote:
> > > 
> > > >Is there a deep reason--mathematical, implementational or
> > > >otherwise--that numbers of type (complex float) can have a zero
> > > >imaginary part while (complex rationals) can not? Or is it just one of
> > > >those things?
> > > >
> > > >-Peter
> > > 
> > > A completely random theory:
> > > 
> > > For a similar reason that when you use, e.g., 10/20, you get 1/2 ?
> > > Or 5/1 -> 5
> > 
> > Actually I was wondering about the other way: I like that 10/20 is
> > just another way of writing 1/2 and that #c(3 0) is just another way
> > of writing 3. I was wondering why, given that, #c(3.0 0.0) is a
> > different object than 3.0.
> 
> But the object #c(3.0 0) is 3.0.

Uh, I don't think so. Per 2.4.8.11 and the dictionary entry for
COMPLEX, the floating point contaigon kicks in first so #c(3.0 0) is
equivalent to #(3.0 0.0) which is then itself. Allegro and SBCL get
this right; CLISP gets it wrong.

  (eql #c(3.0 0) 3.0) ==> NIL ; Allegro and SBCL

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kaz Kylheku
Subject: Re: Why (eql #c(1 0) 1) but (not (eql #c(1.0 0.0) 1.0))?
Date: 
Message-ID: <cf333042.0312060040.563643a4@posting.google.com>
Peter Seibel <·····@javamonkey.com> wrote in message news:<··············@javamonkey.com>...
> Is there a deep reason--mathematical, implementational or
> otherwise--that numbers of type (complex float) can have a zero
> imaginary part while (complex rationals) can not? Or is it just one of
> those things?

According to the HyperSpec, EQL yields T for two numbers that have the
same value **and the same type**.

Note that #c(1 0) is in fact the same thing as 1, effectively an
alternate printed notation for it, the same way as 1/1 is just 1. So
(eql #c(1 0) 1) is de facto equivalent to (eql 1 1). Same value, same
type, thus EQL. If the imaginary part is an integer zero, then the
object is in fact a real or rational! But it has to be an integer
zero. A floating-point imaginary part cannot reduce the complex number
to a real  or rational one. So the real question you appear to be
asking is why isn't #c(1 0.0) considered to be the integer 1, but #c(1
0) is! Well, it's really the same reason why 0.0 isn't considered to
be the integer 0!

Now you want a strict numeric value comparison, there is the =
function! The = function doesn't constrain the types to be the same,
hence, for instance:

(= #c(1 0.0) 1.0) ==> T  

There is even a rule which requires = to descend into complexes: ``Two
complexes are considered equal by = if their real and imaginary parts
are equal according to =.'' The EQL function has no such requirement
for descending into complexes.