A P P E N D I X  E

Standards Compliance

The Sun Studio compiler products together with the header files and libraries in the Solaris 10 operating environment support multiple standards including: System V Interface Definition Edition 3 (SVID), X/Open, ANSI C (C90), POSIX.1-2001 (SUSv3) and ISO C (C99). (See standards(5) for a more complete discussion.) Some of these standards allow implementations to vary in certain respects. In some cases, the specifications of these standards conflict. For the math libraries, the variances and conflicts are primarily related to special cases and exceptions. This appendix documents the behavior of the functions inlibm in these cases and discusses conditions under which a C program can expect behavior that conforms to each standard. The final section of this appendix documents the conformance of the Sun Studio C and Fortran language products to LIA-1.


E.1 libm Special Cases

TABLE E-1 lists all of the cases in which two or more of the standards mentioned above specify conflicting behavior for functions in libm. Which behavior a C program will observe depends on the compiler flags that are used when the program is compiled and linked. Possible behaviors include raising floating point exceptions, calling the user-supplied function matherr with information about the special case that occurred and the value to be returned (see matherr(3M)), printing a message on the standard error file, and setting the global variable errno (see intro(2) and perror(3C)).

The first column in TABLE E-1 defines the special case. The second column shows the value to which errno will be set if it is set at all. The possible values for errno are defined in <errno.h>; the only two values used by the math library are EDOM for domain errors and ERANGE for range errors. When the second column shows both EDOM and ERANGE, the value to which errno is set is determined by the relevant standard as described below and shown in the fourth or fifth column. The third column shows the error code that will be indicated in any error message that is printed. The fourth, fifth, and sixth columns show the function values that will nominally be returned as defined by various standards. In some cases, a user-supplied matherr routine can override these values and supply another return value.

The specific responses to these special cases are determined by the compiler flags specified when a program is linked as follows. If either -xlibmieee or -xc99=lib is specified, then when any of the special cases in TABLE E-1 occurs, any appropriate floating point exceptions are raised, and the function value listed in the sixth column of the table is returned.

If neither -xlibmieee nor -xc99=lib is used, then the behavior depends on the language conformance flag specified when the program is linked.

Specifying the -Xa flag selects X/Open conformance. When any of the special cases in the table occurs, any appropriate floating point exceptions are raised, errno is set, and the function value listed in the fifth column of the table is returned. If a user-defined matherr routine is supplied, the behavior is undefined. Note that -Xa is the default when no other language conformance flag is given.

Specifying the -Xc flag selects strict C90 conformance. When a special case occurs, any appropriate floating point exceptions are raised, errno is set, and the function value listed in the fifth column of the table is returned. matherr is not invoked in this case.

Finally, specifying either the -Xs or the -Xt flag selects SVID conformance. When a special case occurs, any appropriate floating point exceptions are raised, matherr is called, and if matherr returns zero, then errno is set and an error message is printed. The function value listed in the fourth column of the table is returned unless it is overridden by matherr.

See the cc(1) manual page and the Sun Studio C compiler manuals for more information about the -xc99, -Xa, -Xc, -Xs, and -Xt flags.


TABLE E-1 Special Cases and libm Functions

Function

errno

error
message

SVID

X/Open, C90

IEEE, C99, SUSv3

acos(|x|>1)

EDOM

DOMAIN

0.0

0.0

NaN

acosh(x<1)

EDOM

DOMAIN

NaN

NaN

NaN

asin(|x|>1)

EDOM

DOMAIN

0.0

0.0

NaN

atan2(+/-0,+/-0)

EDOM

DOMAIN

0.0

0.0

+/-0.0,+/-pi

atanh(|x|>1)

EDOM

DOMAIN

NaN

NaN

NaN

atanh(+/-1)

EDOM/ERANGE

SING

+/-HUGE1 (EDOM)

+/-HUGE_VAL2 (ERANGE)

+/-infinity

cosh overflow

ERANGE

-

HUGE

HUGE_VAL

infinity

exp overflow

ERANGE

-

HUGE

HUGE_VAL

infinity

exp underflow

ERANGE

-

0.0

0.0

0.0

fmod(x,0)

EDOM

DOMAIN

x

NaN

NaN

gamma(0 or -integer)

EDOM

SING

HUGE

HUGE_VAL

infinity

gamma overflow

ERANGE

-

HUGE

HUGE_VAL

infinity

hypot overflow

ERANGE

-

HUGE

HUGE_VAL

infinity

j0(|x|>X_TLOSS3)

ERANGE

TLOSS

0.0

0.0

correct answer

j1(|x|>X_TLOSS)

ERANGE

TLOSS

0.0

0.0

correct answer

jn(|x|>X_TLOSS)

ERANGE

TLOSS

0.0

0.0

correct answer

lgamma(0 or
-integer)

EDOM

SING

HUGE

HUGE_VAL

infinity

lgamma overflow

ERANGE

-

HUGE

HUGE_VAL

infinity

log(0)

EDOM/ERANGE

SING

-HUGE (EDOM)

-HUGE_VAL (ERANGE)

-infinity

log(x<0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

NaN

log10(0)

EDOM/ERANGE

SING

-HUGE (EDOM)

-HUGE_VAL (ERANGE)

-infinity

log10(x<0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

NaN

log1p(-1)

EDOM/ERANGE

SING

-HUGE (EDOM)

-HUGE_VAL (ERANGE)

-infinity

log1p(x<-1)

EDOM

DOMAIN

NaN

NaN

NaN

pow(0,0)

EDOM

DOMAIN

0.0

1.0 (no error)

1.0 (no error)

pow(NaN,0)

EDOM

DOMAIN

NaN

NaN

1.0 (no error)

pow(0,x<0)

EDOM

DOMAIN

0.0

-HUGE_VAL

+/-infinity

pow(x<0,
non-integer)

EDOM

DOMAIN

0.0

NaN

NaN

pow overflow

ERANGE

-

+/-HUGE

+/-HUGE_VAL

+/-infinity

pow underflow

ERANGE

-

+/-0.0

+/-0.0

+/-0.0

remainder(x,0)

EDOM

DOMAIN

NaN

NaN

NaN

scalb overflow

ERANGE

-

+-HUGE_VAL

+/-HUGE_VAL

+/-infinity

scalb underflow

ERANGE

-

+/-0.0

+/-0.0

+/-0.0

sinh overflow

ERANGE

-

+/-HUGE

+/-HUGE_VAL

+/-infinity

sqrt(x<0)

EDOM

DOMAIN

0.0

NaN

NaN

y0(0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

-infinity

y0(x<0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

NaN

y0(x>X_TLOSS)

ERANGE

TLOSS

0.0

0.0

correct answer

y1(0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

-infinity

y1(x<0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

NaN

y1(x>X_TLOSS)

ERANGE

TLOSS

0.0

0.0

correct answer

yn(n,0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

-infinity

yn(n,x<0)

EDOM

DOMAIN

-HUGE

-HUGE_VAL

NaN

yn(n,x>X_TLOSS)

ERANGE

TLOSS

0.0

0.0

correct answer


Notes:

1. HUGE is defined in <math.h>. SVID requires that HUGE be equal to MAXFLOAT, which is approximately 3.4e+38.

2. HUGE_VAL is defined in <iso/math_iso.h>, which is included in <math.h>. HUGE_VAL evaluates to infinity.

3. X_TLOSS is defined in <values.h>.

E.1.1 Other Compiler Flags Affecting Standard Conformance

The compiler flags listed above directly select which of several standards will be followed in handling the special cases listed in TABLE E-1. Other compiler flags can indirectly affect whether a program observes the behavior described above.

First, both the -xlibmil and -xlibmopt flags substitute faster implementations of some of the functions in libm. These faster implementations do not conform to SVID, X/Open, or C90. Neither do they set errno or call matherr. They do, however, raise floating point exceptions as appropriate and deliver the results specified by IEEE 754 and/or C99. Similar comments apply to the -xvector flag, since it can cause the compiler to transform calls to standard math functions into calls to vector math functions.

Second, the -xbuiltin flag allows the compiler to treat the standard math functions defined in <math.h> as intrinsic and substitute inline code for better performance. The substitute code may not conform to SVID, X/Open, C90, or C99. It need not set errno, call matherr, or raise floating point exceptions.

Third, when the C preprocessor token __MATHERR_ERRNO_DONTCARE is defined, a number of #pragma directives in <math.h> are compiled. These directives tell the compiler to assume that the standard math functions have no side effects. Under this assumption, the compiler can reorder calls to the math functions and references to global data such as errno or data that might be modified by a user-supplied matherr routine so as to violate the expected behavior described above. For example, consider the code fragment:


#include <errno.h>
#include <math.h>
 
...
errno = 0;
x = acos(2.0);
if (errno) {
    printf("error\n");
}

If this code is compiled with __MATHERR_ERRNO_DONTCARE defined, the compiler may assume that errno is not modified by the call to acos and transform the code accordingly, removing the call to printf entirely.

Note that the -fast macro flag includes the flags -xbuiltin, -xlibmil, -xlibmopt, and -D__MATHERR_ERRNO_DONTCARE.

Finally, since all of the math functions in libm raise floating point exceptions as need be, running a program with trapping on those exceptions enabled will generally result in behavior other than that specified by the standards listed above. Thus, the -ftrap compiler flag can also affect standard conformance.

E.1.2 Additional Notes on C99 Conformance

C99 specifies two possible methods by which an implementation can handle special cases such as those in TABLE E-1. An implementation indicates which of the two methods it supports by defining the identifier math_errhandling to evaluate to an integer expression having the value MATH_ERRNO (1) or MATH_ERREXCEPT (2) or the bitwise "or" of these. (These values are defined in <math.h>.) If the expression (math_errhandling & MATH_ERRNO) is nonzero, then the implementation handles cases in which the argument of a function lies outside its mathematical domain by setting errno to EDOM and handles cases in which the result value of a function would underflow, overflow, or equal infinity exactly by setting errno to ERANGE. If the expression (math_errhandling & MATH_ERREXCEPT) is nonzero, then the implementation handles cases in which the argument of a function lies outside its mathematical domain by raising the invalid operation exception and handles cases in which the result value of a function would underflow, overflow or equal infinity exactly by raising the underflow, overflow, or division-by-zero exception, respectively.

On Solaris, <math.h> defines math_errhandling to be MATH_ERREXCEPT. Although the functions listed in TABLE E-1 may perform other actions for the special cases shown there, all libm functions---including the float and long double functions, complex functions, and additional functions specified by C99---respond to special cases by raising floating point exceptions. This is the only method for handling special cases that is supported uniformly for all C99 functions.

Finally, note that there are three functions for which either C99 or SUSv3 requires different behavior from the Solaris default. The differences are summarized in the following table. The table lists only the double version of each function, but the differences apply to the float and long double versions as well. In each case, the SUSv3 specification is followed when a program is linked with -xc99=lib and the Solaris default is followed otherwise.


TABLE E-2 Solaris and C99/SUSv3 Differences

Function

Solaris behavior

C99/SUSv3 behavior

pow

pow(1.0, +/-inf) returns NaN

pow(-1.0, +/-inf) returns NaN

pow(1.0, NaN) returns NaN

pow(1.0, +/-inf) returns 1

pow(-1.0, +/-inf) returns 1

pow(1.0, NaN) returns 1

logb

logb(subnormal) returns Emin

logb(x) = ilogb(x) when x issubnormal

ilogb

ilogb(+/-0), ilogb(+/-inf),

ilogb(NaN) raise no exceptions

ilogb(+/-0), ilogb(+/-inf),

ilogb(NaN) raise invalid operation



E.2 LIA-1 Conformance

In this section, LIA-1 refers to ISO/IEC 10967-1:1994 Information Technology - Language Independent Arithmetic - Part 1: Integer and floating-point arithmetic.

The C and Fortran 95 compilers (cc and f95) contained in the Sun Studio compilers release conform to LIA-1 in the following senses (paragraph letters correspond to those in LIA-1 section 8):

a. TYPES (LIA 5.1): The LIA-1 conformant types are C int and Fortran INTEGER. Other types may conform as well, but they are not specified here. Further specifications for specific languages await language bindings to LIA-1 from the cognizant language standards organizations.

b. PARAMETERS (LIA 5.1):

#include <values.h> /* defines MAXINT */
#define TRUE 1
#define FALSE 0
#define BOUNDED TRUE
#define MODULO TRUE
#define MAXINT 2147483647
#define MININT -2147483648
	logical bounded, modulo
	integer maxint, minint
	parameter (bounded = .TRUE.)
	parameter (modulo = .TRUE.)
	parameter (maxint = 2147483647)
	parameter (minint = -2147483648)

d. DIV/REM/MOD (LIA 5.1.3):

C / and %, and Fortran / and mod(), provide DIVtI(x,y) and REMtI(x,y). Also, modaI(x,y) is available with this code:

int modaI(int x, int y) {
	int t = x % y;
	if (y < 0 && t > 0)
	t -= y;
	else if (y > 0 && t < 0)
	t += y;
		return t;
	}

or this:

	integer function modaI(x, y)
	integer x, y, t
	t = mod(x, y)
	if (y .lt. 0 .and. t .gt. 0) t = t - y
	if (y .gt. 0 .and. t .lt. 0) t = t + y
	modaI = t
	return
	end

i. NOTATION (LIA 5.1.3): The following table shows the notation by which the LIA integer operations may be realized.


TABLE E-3 LIA-1 Conformance - Notation

LIA

C

Fortran if different

addI(x,y)

x+y

 

subI(x,y)

x-y

 

mulI(x,y)

x*y

 

divtI(x,y)

x/y

 

remtI(x,y)

x%y

mod(x,y)

modaI(x,y)

see above

 

negI(x)

-x

 

absI(x)

#include <stdlib.h>

abs(x)

abs(x)

signI(x)

#define signI(x) (x > 0

? 1 : (x < 0 ? -1 : 0))

see below

eqI(x,y)

x==y

x.eq.y

neqI(x,y)

x!=y

x.ne.y

lssI(x,y)

x<y

x.lt.y

leqI(x,y)

x<=y

x.le.y

gtrI(x,y)

x>y

x.gt.y

geqI(x,y)

x>=y

x.ge.y


The following code shows the Fortran notation for signI(x).

	integer function signi(x)
	integer x, t
	if (x .gt. 0) t=1
	if (x .lt. 0) t=-1
	if (x .eq. 0) t=0
	return
	end

j. EXPRESSION EVALUATION: By default, when no optimization is specified, expressions are evaluated in int (C) or INTEGER (Fortran) precision. Parentheses are respected. The order of evaluation of associative unparenthesized expressions such as a + b + c or a * b * c is not specified.

k. METHOD OF OBTAINING PARAMETERS: Include the definitions above in the source code.

n. NOTIFICATION: Integer exceptions are x/0 and x%0 or mod(x,0). By default, these exceptions generate SIGFPE. When no signal handler is specified for SIGFPE, the process terminates and dumps memory.

o. SELECTION MECHANISM: signal(3) or signal(3F) may be used to enable user exception handling for SIGFPE.