/* 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 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 as a "template" to be used with DTYPE in {double, long double, ..} MACH_NAME in {machar, machar_LD, ..} ABS() in {fabs(), fabsl() , ..} */ static void MACH_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 = = 9.0072e+15 for 'double' is used later do { 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; #endif beta = *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; } }