ISO/ IEC JTC1/SC22/WG14 N820

SC22/WG14 N820

Splitting Annex G
Clive D.W. Feather
clive@demon.net
1998-04-15


Abstract
========
In the UK response to CD1 the UK suggested splitting Annex G into two
parts. Annex G currently gives a specification for IEC 559 compatible
complex types *and* for imaginary types, all conflated. These are separate
concepts which can each be useful, and should be separated.

This paper proposes new wording to this end.


Conceptual changes
==================
Annex G is split into two annexes, GI and GC. The former consists of the
old G.2, G.3, and G.6, while the latter consists of G.5 (except one
paragraph). G.1 and G.4 are divided between the two. Both annexes are
normative.

Wherever text appears here without a change bar, it is taken directly
from CD1.

Other references to Annex G are as follows:
  FN28 and FN186 should refer to GI.
  6.8.8 and 7.8.2.1 should refer to GC.
  K.1 should refer to GC.3.


New wording
===========

|                              Annex GI
|                            (normative)

|                          Imaginary Types



  GI.1  Introduction

| [#1] This annex specifies imaginary types. An implementation shall
| either conform to all the requirements of this annex, and shall define
| the macro _Imaginary_I in <complex.h>, or it shall not provide such
| types and shall not define _Imaginary_I.

  GI.2  Types

  [#1]  There  are  three  imaginary  types,  designated  as  float
| _Imaginary,  double _Imaginary,  and long double _Imaginary.  The
  imaginary types (along with the real floating and complex  types)
  are floating types.

  [#2] For imaginary types, the corresponding real type is given by
| deleting the keyword _Imaginary from the type name.

  [#3]  Each  imaginary  type  has  the  same  representation   and
  alignment requirements as the corresponding real type.  The value
  of an  object  of  imaginary  type  is  the  value  of  the  real
  representation times the imaginary unit.

  [#4] The imaginary type-domain comprises the imaginary types.

  GI.3  Conversions

  GI.3.1  Imaginary types

  [#1] Conversions among imaginary types follow rules analogous  to
  those for real floating types.

  GI.3.2  Real and imaginary

  [#1] When a value of imaginary type is converted to a real  type,
  the result is a positive zero.

  [#2] When a value of real type is converted to an imaginary type,
  the result is a positive imaginary zero.

  GI.3.3  Imaginary and complex

  [#1] When a value of imaginary type is  converted  to  a  complex
  type,  the  real  part  of the complex result value is a positive
  zero and the imaginary  part  of  the  complex  result  value  is
  determined  by  the  conversion  rules for the corresponding real
  types.

  [#2] When a value of complex type is converted  to  an  imaginary
  type,  the  real  part  of the complex value is discarded and the
  value of  the  imaginary  part  is  converted  according  to  the
  conversion rules for the corresponding real types.

  GI.4  Binary operators

  [#1] The following subclauses supplement 6.3 in order to  specify
  the  type  of  the  result  for  an  operation  with an imaginary
  operand.

| [#2] For the multiplicative operators, if
  one operand has real  type  and  the  other  operand  has
  imaginary  type,  then  the  result  has imaginary type.  If both
  operands have imaginary type, then the result has real type.  (If
  either  operand  has  complex  type,  then the result has complex
  type.)

| [#3] For the additive operators, if
  one operand has real  type  and  the  other  operand  has
  imaginary  type,  then  the  result  has  complex  type.  If both
  operands have imaginary type, then the result has imaginary type.
  (If  either operand has complex type, then the result has complex
  type.)

  GI.5  <complex.h>

  [#1] The macro

          _Imaginary_I

  is defined, and the macro

          I

  is defined to be _Imaginary_I (7.8).

  GI.6  <tgmath.h>

  [#1] Type-generic  macros  that  accept  complex  arguments  also
  accept  imaginary  arguments.   If  an argument is imaginary, the
  macro expands to an expression whose type is real, imaginary,  or
  complex,  as  appropriate  for  the  particular  function: if the
  argument is imaginary, then the types of cos, cosh,  fabs,  carg,
  cimag,  and  creal  are  real; the types of sin, tan, sinh, tanh,
  asin, atan, asinh, and atanh are imaginary; and the types of  the
  others are complex.

  [#2] Given an imaginary argument, each of the type-generic macros
  cos,  sin,  tan,  cosh,  sinh,  tanh, asin, atan, asinh, atanh is
  specified by a formula in terms of real functions:

          cos(i*y)   = cosh(y)
          sin(i*y)   = i*sinh(y)
          tan(i*y)   = i*tanh(y)
          cosh(i*y)  = cos(y)
          sinh(i*y)  = i*sin(y)
          tanh(i*y)  = i*tan(y)
          asin(i*y)  = i*asinh(y)
          atan(i*y)  = i*atanh(y)
          asinh(i*y) = i*asin(y)
          atanh(i*y) = i*atan(y)






|                              Annex GC
|                             (normative)

|               IEC 559-compatible complex arithmetic



  GC.1  Introduction

| [#1] This annex supplements Annex F to specify complex arithmetic
| for  compatibility  with  IEC 559 real floating-point arithmetic.
| An implementation that defines __STDC_IEC_559_COMPLEX__ conforms to the
| specification in this annex. Where a binding between the C language and
| IEC 559 is indicated, the IEC 559-specified behavior is adopted by
| reference, unless stated otherwise.

  GC.2  Binary operators

  [#1] For most operand types, the value of the result of a  binary
  operator  with  an  imaginary  or  complex  operand is completely
  determined, with reference  to  real  arithmetic,  by  the  usual
  mathematical   formula.    For  some  operand  types,  the  usual
  mathematical formula is problematic because of its  treatment  of
  infinities  and because of undue overflow or underflow;  in these
  cases the  result  satisfies  certain  properties  (specified  in
  this subclause), but is not completely determined.

  GC.2.1  Multiplicative operators

  Semantics

  [#1] If the operands are not both complex, then  the  result  and
  exception  behavior  of  the  *  operator is defined by the usual
  mathematical formula:

  [[table omitted]]

  [#2] If the second operand is not complex, then  the  result  and
  exception  behavior  of  the  /  operator is defined by the usual
  mathematical formula:

  [[table omitted]]

  [#3] A complex or imaginary value with at least one infinite part
  is  regarded as an infinity (even if its other part is a NaN).  A
  complex or imaginary value is a finite  number  if  each  of  its
  parts  is  a finite number (neither infinite nor NaN).  A complex
  or imaginary value is a zero if each of its parts is a zero.  The
  *  and  / operators satisfy the following infinity properties for
  all real, imaginary, and complex operands:289

     - if one operand is an infinity and the  other  operand  is  a
       nonzero finite number or an infinity, then the result of the
       * operator is an infinity;

     - if the first operand is an infinity and the  second  operand
       is  a finite number, then the result of the / operator is an
       infinity;

     - if the first operand is  a  finite  number  and  the  second
       operand is an infinity, then the result of the / operator is
       a zero;

     - if the first operand  is  a  nonzero  finite  number  or  an
       infinity  and  the second operand is a zero, then the result
       of the / operator is an infinity.

  [#4] If both operands of the * operator are  complex  or  if  the
  second  operand of the / operator is complex, the operator raises
  exceptions if appropriate for the calculation of the parts of the
  result, and may raise spurious exceptions.

  Examples

  [#5]

    1.  Multiplication  of  double  complex   operands   could   be
        implemented as follows.  Note that the imaginary unit I has
        imaginary type (see GC.3).

        #include <math.h>
        #include <complex.h>

        /* Multiply z * w ... */
        double complex _Cmultd(double complex z, double complex w)
        {
                #pragma STDC FP_CONTRACT OFF
                double a, b, c, d, ac, bd, ad, bc, x, y;
                a = creal(z); b = cimag(z)
                c = creal(w); d = cimag(w);
                ac = a * c;   bd = b * d;
                ad = a * d;   bc = b * c;
                x = ac - bd;
                y = ad + bc;
                /* Recover infinities that computed as NaN+iNaN ... */
                if (isnan(x) && isnan(y)) {
                        int recalc = 0;
                        if  ( isinf(a) || isinf(b) ) { /* z is infinite */
                                /* "Box" the infinity ... */
                                a = copysign(isinf(a) ? 1.0 : 0.0, a);
                                b = copysign(isinf(b) ? 1.0 : 0.0, b);
                                /* Change NaNs in the other factor to 0 ... */
                                if (isnan(c)) c = copysign(0.0, c);
                                if (isnan(d)) d = copysign(0.0, d);
                                recalc = 1;
                        }
                        if  ( isinf(c) || isinf(d) ) { /* w is infinite */
                                /* "Box" the infinity ... */
                                c = copysign(isinf(c) ? 1.0 : 0.0, c);
                                d = copysign(isinf(d) ? 1.0 : 0.0, d);
                                /* Change NaNs in the other factor to 0 ... */
                                if (isnan(a)) a = copysign(0.0, a);
                                if (isnan(b)) b = copysign(0.0, b);
                                recalc = 1;
                        }
                        if (!recalc) {
                                /* *Recover infinities from overflow cases ... */
                                if (isinf(ac) || isinf(bd) ||
                                        isinf(ad) || isinf(bc)) {
                                        /* Change all NaNs to 0 ... */
                                        if (isnan(a)) a = copysign(0.0, a);
                                        if (isnan(b)) b = copysign(0.0, b);
                                        if (isnan(c)) c = copysign(0.0, c);
                                        if (isnan(d)) d = copysign(0.0, d);
                                        recalc = 1;
                                }
                        }
                        if (recalc) {
                                x = INFINITY * ( a * c - b * d );
                                y = INFINITY * ( a * d + b * c );
                        }
                }
                return x + I * y;
        }

        In  ordinary  (finite)  cases,  the  cost  to  satisfy  the
        infinity  property  for  the  *  operator is only one isnan
        test.   This  implementation  opts  for  performance   over
        guarding against undue overflow and underflow.

    2.  Division  of  two  double   complex   operands   could   be
        implemented as follows.

        #include <math.h>
        #include <complex.h>

        /* Divide z / w ... */
        double complex _Cdivd(double complex z, double complex w)
        {
                #pragma STDC FP_CONTRACT OFF
                double a, b, c, d, logbw, denom, x, y;
                int ilogbw = 0;
                a = creal(z); b = cimag(z);
                c = creal(w); d = cimag(w);
                logbw = logb(fmax(fabs(c), fabs(d)));
                if (isfinite(logbw)) {
                        ilogbw = (int)logbw;
                        c = scalbn(c, -ilogbw);
                        d = scalbn(d, -ilogbw);
                }
                denom = c * c + d * d;
                x = scalbn((a * c + b * d) / denom, -ilogbw);
                y = scalbn((b * c - a * d) / denom, -ilogbw);
                /*
                 * Recover infinities and zeros that computed
                 * as NaN+iNaN; the only cases are non-zero/zero,
                 * infinite/finite, and finite/infinite, ...
                 */
                if (isnan(x) && isnan(y)) {
                        if ((denom == 0.0) &&
                                (!isnan(a) || !isnan(b))) {
                                x = copysign(INFINITY, c) * a;
                                y = copysign(INFINITY, c) * b;
                        }
                        else if ((isinf(a) || isinf(b)) &&
                                isfinite(c) && isfinite(d)) {
                                a = copysign(isinf(a) ? 1.0 : 0.0, a);
                                b = copysign(isinf(b) ? 1.0 : 0.0, b);
                                x = INFINITY * ( a * c + b * d );
                                y = INFINITY * ( b * c - a * d );
                        }
                        else if (isinf(logbw) &&
                                isfinite(a) && isfinite(b)) {
                                c = copysign(isinf(c) ? 1.0 : 0.0, c);
                                d = copysign(isinf(d) ? 1.0 : 0.0, d);
                                x = 0.0 * ( a * c + b * d );
                                y = 0.0 * ( b * c - a * d );
                        }
                }
                return x + I * y;
        }

        [#6] Scaling the denominator alleviates the  main  overflow
        and  underflow  problem,  which  is  more  serious than for
        multiplication.   In  the  spirit  of  the   multiplication
        example  above,  this code does not defend against overflow
        and underflow in the calculation of the numerator.  Scaling
        with   the  scalbn  function,  instead  of  with  division,
        provides better roundoff characteristics.

  GC.2.2  Additive operators

  Semantics

  [#1] In all cases the result and exception behavior of a +  or  -
  operator is defined by the usual mathematical formula:

  [[table omitted]]

  GC.3  <complex.h>

  [#1] This subclause contains specification  for  the  <complex.h>
  functions that is particularly suited to IEC 559 implementations.

  [#2] The functions are continuous onto both sides of their branch
  cuts, taking into account the sign of zero.   For example, csqrt(
  -2 _ 0*I) == _sqrt(2)*I.

  [#3] Since complex and imaginary  values  are  composed  of  real
  values,  each  function  may be regarded as computing real values
  from real values.  Except as  noted,  the  functions  treat  real
  infinities,  NaNs,  signed  zeros,  subnormals, and the exception
  flags in a manner consistent  with  the  specification  for  real
  functions in F.9.

  [#4] The functions  conj,  cimag,  cproj,  and  creal  are  fully
  specified  for  all  implementations,  including IEC 559 ones, in
  7.9.2.  These functions raise no exceptions.

  [#5] Each of the functions  cabs  and  carg  is  specified  by  a
  formula  in  terms  of  a  real function (whose special cases are
  covered in annex F):

          cabs(x + i*y) = hypot(x, y)
          carg(x + i*y) = atan2(y, x)

  [#6] Each of the functions casin, catan, ccos,  csin,  ctan,  and
  cpow  is  specified  implicitly  by  a  formula in terms of other
  complex functions (whose special cases are specified below):

          casin(z)    = -i*casinh(i*z)
          catan(z)    = -i*catanh(i*z)
          ccos(z)     =    ccosh(i*z)
          csin(z)     = -i*csinh(i*z)
          ctan(z)     = -i*ctanh(i*z)
          cpow(z, c)  =    cexp(c * clog(z))

  [#7] For the other functions, the  following  subclauses  specify
  behavior  for  special  cases, including treatment of the invalid
  and divide-by-zero  exceptions.   For  a  function  f  satisfying
  f(conj(z))  =  conj(f(z)),  the specification for the upper half-
  plane implies the specification for  the  lower  half-plane;   if
  also the function f is either even, f(-z) = f(z), or odd, f(-z) =
   -f(z), then the specification for the first quadrant implies the
  specification for the other three quadrants.

  GC.3.1  The cacos function

  [#1]

     - cacos(conj(z)) = conj(cacos(z)).

     - cacos(_0+i0) returns pi/2-i0.

     - cacos(-oo+ioo) returns 3pi/4-ioo.

     - cacos(+oo+ioo) returns pi/4-ioo.

     - cacos(x+ioo) returns pi/2-ioo, for finite x.

     - cacos(-oo+iy) returns pi-ioo, for positive-signed finite y.

     - cacos(+oo+iy) returns +0-ioo, for positive-signed finite y.

     - cacos(_oo+iNAN) returns NaN_i oo  (where  the  sign  of  the
       imaginary part of the result is unspecified).

     - cacos(_0+iNAN) returns pi/2+iNaN.

     - cacos(NAN+ioo) returns NaN-ioo.

     - cacos(x+iNAN) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for nonzero finite x.

     - cacos(NAN+iy) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite y.

     - cacos(NAN+iNAN) returns NaN+iNaN.

  GC.3.2  The cacosh function

  [#1]

     - cacosh(conj(z)) = conj(cacosh(z)).

     - cacosh(_0+i0) returns +0+ipi/2.

     - cacosh(-oo+ioo) returns +oo+i3pi/4.

     - cacosh(+oo+ioo) returns +oo+ipi/4.

     - cacosh(x+ioo) returns +oo+ipi/2, for finite x.

     - cacosh(-oo+iy) returns +oo+ipi, for  positive-signed  finite
       y.

     - cacosh(+oo+iy) returns +oo+i0, for positive-signed finite y.

     - cacosh(NAN+ioo) returns +oo+iNaN.

     - cacosh(_oo+iNAN) returns +oo+iNaN.

     - cacosh(x+iNAN) returns NaN+iNaN and  optionally  raises  the
       invalid exception, for finite x.

     - cacosh(NAN+iy) returns NaN+iNaN and  optionally  raises  the
       invalid exception, for finite y.

     - cacosh(NAN+iNAN) returns NaN+iNaN.

  GC.3.3  The casinh function

     - casinh(conj(z)) = conj(casinh(z)) and casinh is odd.

     - casinh(+0+i0) returns 0+i0.

     - casinh(oo+ioo) returns +oo+ipi/4.

     - casinh(x+ioo) returns +oo+ipi/2 for  positive-signed  finite
       x.

     - casinh(+oo+iy) returns +oo+i0 for positive-signed finite y.

     - casinh(NAN+ioo) returns _oo+iNaN (where the sign of the real
       part of the result is unspecified).

     - casinh(+oo+iNAN) returns +oo+iNaN.

     - casinh(NAN+i0) returns NaN+i0.

     - casinh(NAN+iy) returns NaN+iNaN and  optionally  raises  the
       invalid exception, for finite nonzero y.

     - casinh(x+iNAN) returns NaN+iNaN and  optionally  raises  the
       invalid exception, for finite x.

     - casinh(NAN+iNAN) returns NaN+iNaN.

  GC.3.4  The catanh function

  [#1]

     - catanh(conj(z)) = conj(catanh(z))and catanh is odd.

     - catanh(+0+i0) returns +0+i0.

     - catanh(+oo+ioo) returns +0+ipi/2.

     - catanh(+oo+iy) returns +0+ipi/2, for finite  positive-signed
       y.

     - catanh(x+ioo) returns +0+ipi/2, for  finite  positive-signed
       x.

     - catanh(+0+iNAN) returns +0+iNaN.

     - catanh(NAN+ioo) returns _0+ipi/2 (where the sign of the real
       part of the result is unspecified).

     - catanh(+oo+iNAN) returns +0+iNaN.

     - catanh(NAN+iy) returns NaN+iNaN and  optionally  raises  the
       invalid exception, for finite y.

     - catanh(x+iNAN) returns NAN+iNAN and  optionally  raises  the
       invalid exception for nonzero finite x.

     - catanh(NAN+iNAN) returns NaN+iNaN.

  GC.3.5  The ccosh function

  [#1]

     - ccosh(conj(z)) = conj(ccosh(z)) and ccosh is even.

     - ccosh(+0+i0) returns 1+i0.

     - ccosh(+0+ioo)  returns  NaN _ i0  (where  the  sign  of  the
       imaginary  part of the result is unspecified) and raises the
       invalid exception.

     - ccosh(+oo+i0) returns +oo+i0.

     - ccosh(+oo+ioo) returns +oo + iNaN  and  raises  the  invalid
       exception.

     - ccosh(x+ioo)  returns  NaN + iNaN  and  raises  the  invalid
       exception, for finite nonzero x.

     - ccosh(+oo+iy) returns (+oo)*cis(y), for finite nonzero y.290

     - ccosh(+0+iNaN) returns  NaN _ i0  (where  the  sign  of  the
       imaginary part of the result is unspecified).

     - ccosh(+oo+iNaN) returns +oo+iNaN.

     - ccosh(x+iNAN) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite nonzero x.

     - ccosh(NAN+i0)  returns  NaN _ i0  (where  the  sign  of  the
       imaginary part of the result is unspecified).

     - ccosh(NAN+iy) returns NAN+iNAN  and  optionally  raises  the
       invalid exception, for all nonzero numbers y.

     - ccosh(NAN+iNAN) returns NaN+iNaN.

  GC.3.6  The csinh function

  [#1]

     - csinh(conj(z)) = conj(csinh(z)) and csinh is odd.

     - csinh(+0+i0) returns +0+i0.

     - csinh(+0+ioo) returns _0+iNaN (where the sign  of  the  real
       part  of  the  result is unspecified) and raises the invalid
       exception.

     - csinh(+oo+i0) returns +oo+i0.

     - csinh(+oo+ioo) returns _oo+iNaN (where the sign of the  real
       part  of  the  result is unspecified) and raises the invalid
       exception.

     - csinh(+oo+iy) returns (+oo)*cis(y), for positive finite y.

     - csinh(x+ioo)  returns  NaN + iNaN  and  raises  the  invalid
       exception, for positive finite x.

     - csinh(+0+iNAN) returns _0+iNaN (where the sign of  the  real
       part of the result is unspecified).

     - csinh(+oo+iNAN) returns _oo+iNaN (where the sign of the real
       part of the result is unspecified).

     - csinh(x+iNAN) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite nonzero x.

     - csinh(NAN+i0) returns NaN+i0.

     - csinh(NAN+iy) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for all nonzero numbers y.

     - csinh(NAN+iNAN) returns NaN+iNaN.

  GC.3.7  The ctanh function

  [#1]

     - ctanh(conj(z)) = conj(ctanh(z))and ctanh is odd.

     - ctanh(+0+i0) returns +0+i0.

     - ctanh(+oo+iy) returns 1+i0, for all positive-signed  numbers
       y.

     - ctanh(x+ioo)  returns  NaN + iNaN  and  raises  the  invalid
       exception, for finite x.

     - ctanh(+oo+iNAN)  returns  1 _ i0  (where  the  sign  of  the
       imaginary part of the result is unspecified).

     - ctanh(NAN+i0) returns NaN+i0.

     - ctanh(NAN+iy) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for all nonzero numbers y.

     - ctanh(x+iNAN) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite x.

     - ctanh(NAN+iNAN) returns NaN+iNaN.

  GC.3.8  The cexp function

  [#1]

     - cexp(conj(z)) = conj(cexp(z)).

     - cexp(_0+i0) returns 1+i0.

     - cexp(+oo+i0) returns +oo+i0.

     - cexp(-oo+ioo) returns _0_i0 (where the signs of the real and
       imaginary parts of the result are unspecified).

     - cexp(+oo+ioo) returns _ oo + iNaN  and  raises  the  invalid
       exception  (where the sign of the real part of the result is
       unspecified).

     - cexp(x+ioo )  returns  NaN + iNaN  and  raises  the  invalid
       exception, for finite x.

     - cexp(-oo+iy) returns +0*cis(y), for finite y.

     - cexp(+oo+iy) returns +oo*cis(y), for finite nonzero y.

     - cexp(-oo+iNAN) returns _0_i0 (where the signs  of  the  real
       and imaginary parts of the result are unspecified).

     - cexp(+oo+iNAN) returns _oo+iNaN (where the sign of the  real
       part of the result is unspecified).

     - cexp(NAN+i0) returns NaN+i0.

     - cexp(NAN+iy) returns NaN+ iNaN  and  optionally  raises  the
       invalid exception, for all non-zero numbers y.

     - cexp(x+iNAN) returns NaN+ iNaN  and  optionally  raises  the
       invalid exception, for finite x.

     - cexp(NAN+iNAN) returns NaN+iNaN.

  GC.3.9  The clog function

  [#1]

     - clog(conj(z)) = conj(clog(z)).

     - clog(-0+i0) returns -oo+ipi and  raises  the  divide-by-zero
       exception.

     - clog(+0+i0) returns -oo+i0  and  raises  the  divide-by-zero
       exception.

     - clog(-oo+ioo) returns +oo+i3pi/4.

     - clog(+oo+ioo) returns +oo+ipi/4.

     - clog(x+ioo) returns +oo+ipi/2, for finite x.

     - clog(-oo+iy) returns +oo+ipi, for finite positive-signed y.

     - clog(+oo+iy) returns +oo+i0, for finite positive-signed y.

     - clog(_oo+iNAN) returns +oo+iNaN.

     - clog(NAN+ioo) returns +oo+iNaN.

     - clog(x+iNAN) returns NaN+ iNaN  and  optionally  raises  the
       invalid exception, for finite x.

     - clog(NAN+iy) returns NaN+ iNaN  and  optionally  raises  the
       invalid exception, for finite y.

     - clog(NAN+iNAN) returns NaN+iNaN.

  GC.3.10  The csqrt function

  [#1]

     - csqrt(conj(z)) = conj(csqrt(z)).

     - csqrt(_0+i0) returns +0+i0.

     - csqrt(-oo+iy) returns +0+ioo, for finite positive-signed y.

     - csqrt(+oo+iy) returns +oo+i0, for finite positive-signed y.

     - csqrt(x+ioo) returns +oo+ioo, for all x (including NaN).

     - csqrt(-oo+iNAN) returns NaN_i oo  (where  the  sign  of  the
       imaginary part of the result is unspecified).

     - csqrt(+oo+iNAN) returns +oo+iNaN.

     - csqrt(x+iNAN) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite x.

     - csqrt(NAN+iy) returns NaN+iNaN  and  optionally  raises  the
       invalid exception, for finite y.

     - csqrt(NAN+iNAN) returns NaN+iNaN.

  __________

  289. These properties are already implied for those cases covered
      in the tables, but are required for all cases (at least where
      the state for CX_LIMITED_RANGE is off).

  290. cis(y) is defined by cos(y)+i*sin(y).