!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 No Action (6-0-0) 04-06-14 !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. ****************************************************************