!standard G.01.01(58) 04-04-26 AI95-00380/00
!standard 11.04.01(12)
!standard 11.04.01(13)
!class binding interpretation 04-04-26
!status received 04-04-19
!priority Low
!difficulty Medium
!subject Sign of zero in complex values
!summary
!question
How do you construct a complex value with a particular sign on the real or
imaginary parts? G.1.1(58) is only Implementation Advice, and only requires
that "implementations attempt rational treatment of signs...". If you need
a particular sign (for instance, to insure that a particular branch of a
function is invoked), there doesn't appear to be any way to get one.
Even operations that do not involve any math (such as Compose_from_Cartesian)
do not necessarily preserve the sign of their operands.
!wording
--!corrigendum
!example
!ACATS test
ACATS CXG2020 prompted this question.
!appendix
!topic Signed zeros when creating a complex number
!reference G.1.1(53,57)
!from Adam Beneschan 04-04-19
!discussion
G.1.1(53) says: "The sign of a zero result or zero result component
yielded by a complex arithmetic operation or function is
implementation defined when Real'Signed_Zeros is True". G.1.1(57)
contains some implementation advice about not promoting a real operand
to a complex operand when performing addition or subtraction between a
real and a complex operand.
I don't know what the rationale is behind not *requiring* that the
signs of zeros be preserved when nothing is added, but I imagine there
must be one. Thus, when calling this operation:
function "+" (Left : Complex; Right : Real'Base) return Complex
when Left.Im is 0.0, it appears that the Im component of the result is
not required to have the same sign as Left.Im when Real'Signed_Zeros
is True. G.1.1(57) seems to make it "Implementation Advice" that the
sign of Left.Im be preserved, but doesn't say so explicitly.
In any case, I'm sure that there's a reason. What surprised me, while
looking into an ACATS test (and after a bit of discussion with Randy)
is that we found that G.1.1(53) appears to apply to *all* functions,
including
function Compose_From_Cartesian (Re, Im : Real'Base) return Complex;
Since this operation doesn't involve any actual arithmetic, it seems
to me that it should be required to preserve the sign of any zero
argument if 'Signed_Zeros is True. Is this a flaw in the RM that this
isn't a requirement?
Similarly, the "+" and "-" binary functions where one operand is
Real'Base and the other operand is Imaginary don't involve any actual
addition or subtraction, so it seems that the signs of any zero
operands should be preserved (or reversed, for the right operand of
"-"). Is there a reason this shouldn't be required?
The latter came up in one of the ACATS tests, cxg2020, which used this
expression:
-1.0-0.0*i
and expected that the Im part of the result of the binary "-" would be
-0.0, which then affected the result of Sqrt (G.1.2(38-39)). On
studying this closely it appears that there is no requirement that the
result of -1.0-0.0*i have an imaginary part with a negative sign.
Thoughts? I don't know whether there's any compiler that doesn't
follow G.1.1(57), so this might be a purely academic issue.
(Also, is there any support for adding a 'Signed_Zeroes attribute that
is equivalent to 'Signed_Zeros? Both are correct in English, and I
find it quite difficult to avoid typing the extra "e". OK, this isn't
a real serious issue, but it is annoying to me. Queuing_Policy is
another annoyance---I keep wanting to add an "e" before the first
"i", which is another correct English spelling.)
****************************************************************
From: John Barnes
Sent: Tuesday, April 20, 2004 1:32 AM
On the spelling issue. Zeros and Queuing are the preferred forms according
to Fowler and the Shorter Oxford Dictionary.
Adding Signed_Zeroes will encourage the illiterate to ask for Finalise as
well and that would create a real old mess!
****************************************************************
From: Robert A. Duff
Sent: Tuesday, April 20, 2004 8:28 AM
Yeah, but "queueing" has five vowels in a row. I think it's the only
such English word. For that reason, I pushed the MRT to use this
spelling in the RM.
I would never push for *both*, though.
****************************************************************
From: Pascal Leroy
Sent: Tuesday, April 20, 2004 3:19 AM
> Thoughts? I don't know whether there's any compiler that
> doesn't follow G.1.1(57), so this might be a purely academic issue.
I think the IA in G.1.1(57-58) is just fine as it is. Being more
specific would require a lot of additional RM wording, and would not buy
much since implementers are likely to do the right thing anyway.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, April 20, 2004 3:28 PM
Well, the IA may be fine, but then the question is how do you write tests?
(And how do users that care cope?) There is no guarantee that -1.0-0.0*i or
any other expression creates/preserves a signed zero. Even if you used a
function to create the signed zero (which already exists in the ACATS and
the test in question should have used), there is no guarantee that the value
would end up with the proper sign.
Are you seriously saying that all of the complex signed zero subtests should
be deleted? (The implementation advice isn't specific enough even to make
the tests conditional on it.)
Testing probably isn't that important (and testing questions really don't
belong here), but that gets to the crux of the question. If you care about
signed zeros (I admit I have no idea why anyone would even want such a
thing, but I presume there is some reason or it wouldn't have all of the
effort put into it), the fact this is IA says that you cannot use trust
their use with complex numbers. That seems wrong, especially when the "easy"
cases could be specified.
****************************************************************
From: Jean-Pierre Rosen
Sent: Wednesday, April 21, 2004 1:35 AM
As far as I understood, the main use of signed zeroes is to a avoid a
2*PI jump when computing Artan (Y/X), and Y underflows from the negative
side. It is harder to imagine the importance of it for complex numbers,
but maybe I should revise some maths that have been covered by dust for
(hmmm) 30 years now.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, April 21, 2004 3:55 AM
> If you care about signed zeros (I admit I have no
> idea why anyone would even want such a thing, but I presume
> there is some reason or it wouldn't have all of the effort
> put into it)...
The reason why signed zeros are important has to do with the branch cuts
of complex functions. Most of the interesting complex functions have
branch cuts. Furthermore, all analytic functions have branch cut that
fall on the imaginary or real axis. The distinction between +0.0 and
-0.0 indicates an what side of the branch cut you fall, and it makes a
big difference in for the final value of the function (typically it
changes the sign of a non-zero quantity).
If you really care about signed zeros and your implementation doesn't do
the right thing, you will quickly notice and you will talk sternly to
your compiler vendor.
> Are you seriously saying that all of the complex signed zero
> subtests should be deleted? (The implementation advice isn't
> specific enough even to make the tests conditional on it.)
No, I am saying that G.1.1(56-57) provide sufficient ground for writing
tests that ensure that signed zeros are correctly produced in the cases
described by these two paragraphs. These tests are useful for
implementers to ensure that they didn't screw up, and they are
relatively straightforward to write. Because this is an IA, I suppose
that an implementer could petition the test if they are using an
implementation technique that cannot possibly support the behavior
mandated by the IA, but I expect this to be a rare occurrence.
G.1.1(58) on the other hand is completely untestable.
If you want to write the wording to make G.1.1(56-57), be my guest, but
this is more complicated than it seems, and it would have zero impact on
either implementers or users, so there are probably better uses of your
time.
And don't even try for G.1.1(58), it's hopeless.
> Testing probably isn't that important (and testing questions
> really don't belong here)
Right, I suppose this is a question for the FRT.
****************************************************************
From: Ed Schonberg
Sent: Wednesday, April 21, 2004 7:47 AM
> Furthermore, all analytic functions have branch cut that
> fall on the imaginary or real axis.
Fortunately this is not in annex G... Some interesting analytic functions
may have branch cuts, but rational functions, for example, have none.
****************************************************************
From: Pascal Leroy
Sent: Thursday, April 22, 2004 1:43 AM
This was poorly phrased, wasn't it? It should have read: "For all analytic
functions that have branch cuts, the cuts fall on the imaginary or real
axis." Of course, not all analytic functions have branch cuts...
****************************************************************
From: Michael F. Yoder
Sent: Wednesday, April 21, 2004 1:07 PM
Signed zeros were originally for interval arithmetic, where (for
multiplication and division) it's important to distinguish whether zero
is in an interval or not. Afterward, the uses for distinguishing sides
of a branch cut in the complex plane were noted. There are algorithms
(e.g. conformal mapping of polygons, IIRC) where having signed zeros is
essential or highly desirable.
As far as the discussion is concerned, I'm much more on the side of
making things precise than not. Nor should the fact that covering all
cases is pragmatically impossible (or at least very hard) block covering
the simple and clear ones: this would be making the best the enemy of
the good.
****************************************************************
From: John Halleck
Sent: Wednesday, April 21, 2004 9:11 AM
> The reason why signed zeros are important has to do with the branch cuts
> of complex functions.
Probably... but as an old Univac programmer at the time ADA
was being developed, I've always assumed a different reason
for explictly mentioning signed zeros.
The underlying hardware on many machines was one's complement.
(Univac 1100's, for example, and (if I remember correctly) Crays's)
One's complement representations naturally have signed zeros.
(Whether you want them or not.)
For ADA (back before IEEE floating point became the norm)
the issue had to be addressed, or make life ugly for a
significant chunk of the machines owned by the government
that was funding the work on ADA.
Just my personal opinion...
****************************************************************
From: Pascal Leroy
Sent: Thursday, April 22, 2004 1:56 AM
I don't think this is related. The Univac had 1's complement integers, and
true, Ada always had provisions for making integer ranges symmetric to
support this type of hardware.
However, we are discussing floating-point types here, and most
floating-point hardware use a 1's complement representation (in fact I
cannot remember the last time that I saw a 2's complement floating-point
representation). So for the vast majority of hardware out there, signed
zeros do exist, but it's only in Ada 95 that they were made visible at the
language level. I believe that complex functions were the main reason for
adding this capability, as in other contexts +0.0 and -0.0 look very much
alike. (Note that Mike Y's example of conformal mapping of polygons has to
do with analytic complex functions, too.)
****************************************************************
From: John Halleck
Sent: Thursday, April 22, 2004 9:35 AM
> I don't think this is related. The Univac had 1's complement integers, and
And one's complement reals.
I'm not sure what point you are making by pointing out that the
integers were also one's complement.
> true, Ada always had provisions for making integer ranges symmetric to
> support this type of hardware.
I'm still not sure why you are bringing up integers.
> However, we are discussing floating-point types here, and most
You brought up integers above... the only mention of integers
as been yours.
> floating-point hardware use a 1's complement representation (in fact I
> cannot remember the last time that I saw a 2's complement floating-point
> representation). So for the vast majority of hardware out there, signed
> zeros do exist, but it's only in Ada 95 that they were made visible at the
> language level.
Although at the time ADA was developed both 1's and 2's complement
floating point representations were in use.
> adding this capability, as in other contexts +0.0 and -0.0 look very much
> alike. (Note that Mike Y's example of conformal mapping of polygons has to
> do with analytic complex functions, too.)
As I said, that was probably the the reason...
but underlying one's complement reasons also argue for specific mention
even if that wasn't the case.
****************************************************************
From: Michael F. Yoder
Sent: Friday, April 23, 2004 9:10 AM
With respect to branch cuts: these are entirely a matter of choice, and
so eventually of convention. Nothing stops me from defining a version
of square root with a branch cut that is a sine wave starting at the
origin and proceeding at a 45-degree angle to both axes. Indeed, if a
function has a branch point not on an axis, it's impossible for a branch
cut to lie entirely on an axis: sqrt(z - 1 - i) is such a function,
having a branch point at 1+i. (I'm using the terminology of Ahlfors,
_Complex Analysis_.)
If a function is analytic at 0, Abel summation of the Taylor series
yields a function analytic everywhere except points on rays extending
from the singularities away from the origin (Hardy, _Divergent Series_,
8.10.) This region is called the Mittag-Leffler star of the function.
This means that, in the absence of other considerations, the most
natural set of cuts for a function is arguably the complement of its
Mittag-Leffler star, which will lie on the axes if all singularities do.
For the functions in question, there is a stronger consideration,
namely that we are extending real-valued functions on subsets of the
real line, and we want the cuts to avoid the subset of the x-axis that
corresponds to that domain. These considerations explain the usual
mathematical conventions; but there have been variations in definition
for the inverse trigonometric functions (Spanier and Oldham, _An Atlas
of Functions_ , p. 340).
All that aside, the RM conventions match the most common conventions to
the best of my knowledge.
****************************************************************