Rev 78364 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* Formerly src/appl/machar.c:* void machar() -- computes ALL `machine constants' at once.* ------------- -- compare with ../nmath/i1mach.c & ../nmath/d1mach.c* which use the C <float.h> constants !* algorithm 665, collected algorithms from acm.* this work published in transactions on mathematical software,* vol. 14, no. 4, pp. 303-311.** this fortran 77 subroutine is intended to determine the parameters* of the floating-point arithmetic system specified below. the* determination of the first three uses an extension of an algorithm* due to m. malcolm, cacm 15 (1972), pp. 949-951, incorporating some,* but not all, of the improvements suggested by m. gentleman and s.* marovich, cacm 17 (1974), pp. 276-277. an earlier version of this* program was published in the book software manual for the* elementary functions by w. j. cody and w. waite, prentice-hall,* englewood cliffs, nj, 1980.** the program as given here must be modified before compiling. if* a single (double) precision version is desired, change all* occurrences of cs ( ) in columns 1 and 2 to blanks.** parameter values reported are as follows:** ibeta - the radix for the floating-point representation* it - the number of base ibeta digits in the floating-point* significand* irnd - 0 if floating-point addition chops* 1 if floating-point addition rounds, but not in the* ieee style* 2 if floating-point addition rounds in the ieee style* 3 if floating-point addition chops, and there is* partial underflow* 4 if floating-point addition rounds, but not in the* ieee style, and there is partial underflow* 5 if floating-point addition rounds in the ieee style,* and there is partial underflow* ngrd - the number of guard digits for multiplication with* truncating arithmetic. it is* 0 if floating-point arithmetic rounds, or if it* truncates and only it base ibeta digits* participate in the post-normalization shift of the* floating-point significand in multiplication;* 1 if floating-point arithmetic truncates and more* than it base ibeta digits participate in the* post-normalization shift of the floating-point* significand in multiplication.* machep - the largest negative integer such that* 1.0+float(ibeta)**machep .ne. 1.0, except that* machep is bounded below by -(it+3)* negeps - the largest negative integer such that* 1.0-float(ibeta)**negeps .ne. 1.0, except that* negeps is bounded below by -(it+3)* iexp - the number of bits (decimal places if ibeta = 10)* reserved for the representation of the exponent* (including the bias or sign) of a floating-point* number* minexp - the largest in magnitude negative integer such that* float(ibeta)**minexp is positive and normalized* maxexp - the smallest positive power of beta that overflows* eps - the smallest positive floating-point number such* that 1.0+eps .ne. 1.0. in particular, if either* ibeta = 2 or irnd = 0, eps = float(ibeta)**machep.* otherwise, eps = (float(ibeta)**machep)/2* epsneg - a small positive floating-point number such that* 1.0-epsneg .ne. 1.0. in particular, if ibeta = 2* or irnd = 0, epsneg = float(ibeta)**negeps.* otherwise, epsneg = (ibeta**negeps)/2. because* negeps is bounded below by -(it+3), epsneg may not* be the smallest number that can alter 1.0 by* subtraction.* xmin - the smallest non-vanishing normalized floating-point* power of the radix, i.e., xmin = float(ibeta)**minexp* xmax - the largest finite floating-point number. in* particular xmax = (1.0-epsneg)*float(ibeta)**maxexp* note - on some machines xmax will be only the* second, or perhaps third, largest number, being* too small by 1 or 2 units in the last digit of* the significand.** latest revision - april 20, 1987** author - w. j. cody* argonne national laboratory**//* #include from ./platform.c , now asa "template" to be used with DTYPE in {double, long double, ..}MACH_NAME in {machar, machar_LD, ..}ABS() in {fabs(), fabsl() , ..}*/static voidMACH_NAME(int *ibeta, int *it, int *irnd, int *ngrd, int *machep, int *negep,int *iexp, int *minexp, int *maxexp,DTYPE *eps, DTYPE *epsneg, DTYPE *xmin, DTYPE *xmax){volatile DTYPE a, b, beta, betain, betah, one,t, temp, tempa, temp1, two, y, z, zero;int i, iz, j, k, mx, nxres;one = 1;two = one+one;zero = one-one;/* determine ibeta, beta ala malcolm. */a = one; // a = <large> = 9.0072e+15 for 'double' is used laterdo {a = a + a;temp = a + one;temp1 = temp - a;}while(temp1 - one == zero);#ifdef _no_longer___did_overflow_ // on IBM PowerPPC ('Power 8')int itemp;b = one;do {b = b + b;temp = a + b;itemp = (int)(temp - a);}while (itemp == 0);*ibeta = itemp;#else*ibeta = (int) FLT_RADIX;#endifbeta = *ibeta;/* determine it, irnd */*it = 0;b = one;do {*it = *it + 1;b = b * beta;temp = b + one;temp1 = temp - b;}while(temp1 - one == zero);*irnd = 0;betah = beta / two;temp = a + betah;if (temp - a != zero)*irnd = 1;tempa = a + beta;temp = tempa + betah;if (*irnd == 0 && temp - tempa != zero)*irnd = 2;/* determine negep, epsneg */*negep = *it + 3;betain = one / beta;a = one;for(i=1 ; i<=*negep ; i++)a = a * betain;b = a;for(;;) {temp = one - a;if (temp - one != zero)break;a = a * beta;*negep = *negep - 1;}*negep = -*negep;*epsneg = a;if (*ibeta != 2 && *irnd != 0) {a = (a * (one + a)) / two;temp = one - a;if (temp - one != zero)*epsneg = a;}/* determine machep, eps */*machep = -*it - 3;a = b;for(;;) {temp = one + a;if (temp - one != zero)break;a = a * beta;*machep = *machep + 1;}*eps = a;temp = tempa + beta * (one + *eps);if (*ibeta != 2 && *irnd != 0) {a = (a * (one + a)) / two;temp = one + a;if (temp - one != zero)*eps = a;}/* determine ngrd */*ngrd = 0;temp = one + *eps;if (*irnd == 0 && temp * one - one != zero)*ngrd = 1;/* determine iexp, minexp, xmin *//* loop to determine largest i and k = 2**i such that *//* (1/beta) ** (2**(i)) *//* does not underflow. *//* exit from loop is signaled by an underflow. */i = 0;k = 1;z = betain;t = one + *eps;nxres = 0;for(;;) {y = z;z = y * y;/* check for underflow here */a = z * one;temp = z * t;if (a+a == zero || ABS(z) >= y)break;temp1 = temp * betain;if (temp1 * beta == z)break;i = i+1;k = k+k;}if (*ibeta != 10) {*iexp = i + 1;mx = k + k;}else {/* this segment is for decimal machines only */*iexp = 2;iz = *ibeta;while (k >= iz) {iz = iz * *ibeta;iexp = iexp + 1;}mx = iz + iz - 1;}do {/* loop to determine minexp, xmin *//* exit from loop is signaled by an underflow */*xmin = y;y = y * betain;/* check for underflow here */a = y * one;temp = y * t;if (a+a == zero || ABS(y) >= *xmin)goto L10;k = k + 1;temp1 = temp * betain;}while(temp1 * beta != y);nxres = 3;*xmin = y;L10: *minexp = -k;/* determine maxexp, xmax */if (mx <= k + k - 3 && *ibeta != 10) {mx = mx + mx;*iexp = *iexp + 1;}*maxexp = mx + *minexp;/* adjust irnd to reflect partial underflow */*irnd = *irnd + nxres;/* adjust for ieee-style machines */if (*irnd == 2 || *irnd == 5)*maxexp = *maxexp - 2;/* adjust for non-ieee machines with partial underflow */if (*irnd == 3 || *irnd == 4)*maxexp = *maxexp - *it;/* adjust for machines with implicit leading bit in binary *//* significand, and machines with radix point at extreme *//* right of significand. */i = *maxexp + *minexp;if (*ibeta == 2 && i == 0)*maxexp = *maxexp - 1;if (i > 20)*maxexp = *maxexp - 1;if (a != y)*maxexp = *maxexp - 2;*xmax = one - *epsneg;if (*xmax * one != *xmax)*xmax = one - beta * *epsneg;*xmax = *xmax / (beta * beta * beta * *xmin);i = *maxexp + *minexp + 3;if (i>0)for(j=1 ; j<=i ; j++) {if (*ibeta == 2)*xmax = *xmax + *xmax;if (*ibeta != 2)*xmax = *xmax * beta;}}