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).

AltStyle によって変換されたページ (->オリジナル) /