Octave logo Octave-Forge - Extra packages for GNU Octave
Home · Packages · Developers · Documentation · Function Reference · FAQ · Bugs · Mailing Lists · Links · SVN
  • Main Page
  • Classes
  • Files

libcruft/misc/machar.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <float.h>
00006 
00007 #ifndef TEST
00008 #include "f77-fcn.h"
00009 #endif
00010 
00011 /*
00012 
00013 This file combines the single and double precision versions of machar,
00014 selected by cc -DSP or cc -DDP.  This feature provided by D. G. Hough,
00015 August 3, 1988.
00016 
00017 */
00018 
00019 #ifdef SP
00020 #define REAL float
00021 #define ZERO 0.0
00022 #define ONE 1.0
00023 #define PREC "Single "
00024 #define REALSIZE 1
00025 #endif
00026 
00027 #ifdef DP
00028 #define REAL double
00029 #define ZERO 0.0e0
00030 #define ONE 1.0e0
00031 #define PREC "Double "
00032 #define REALSIZE 2
00033 #endif
00034 
00035 #include <math.h>
00036 #include <stdio.h>
00037 
00038 #define ABS(xxx) ((xxx>ZERO)?(xxx):(-xxx))
00039 
00040 void
00041 rmachar(int *ibeta, int *it, int *irnd, int *ngrd, int *machep,
00042         int *negep, int *iexp, int *minexp, int *maxexp, REAL *eps,
00043         REAL *epsneg, REAL *xmin, REAL *xmax)
00044 
00045 /*
00046 
00047    This subroutine is intended to determine the parameters of the
00048     floating-point arithmetic system specified below.  The
00049     determination of the first three uses an extension of an algorithm
00050     due to M. Malcolm, CACM 15 (1972), pp. 949-951, incorporating some,
00051     but not all, of the improvements suggested by M. Gentleman and S.
00052     Marovich, CACM 17 (1974), pp. 276-277.  An earlier version of this
00053     program was published in the book Software Manual for the
00054     Elementary Functions by W. J. Cody and W. Waite, Prentice-Hall,
00055     Englewood Cliffs, NJ, 1980.  The present program is a
00056     translation of the Fortran 77 program in W. J. Cody, "MACHAR:
00057     A subroutine to dynamically determine machine parameters".
00058     TOMS (14), 1988.
00059 
00060    Parameter values reported are as follows:
00061 
00062         ibeta   - the radix for the floating-point representation
00063         it      - the number of base ibeta digits in the floating-point
00064                   significand
00065         irnd    - 0 if floating-point addition chops
00066                   1 if floating-point addition rounds, but not in the
00067                     IEEE style
00068                   2 if floating-point addition rounds in the IEEE style
00069                   3 if floating-point addition chops, and there is
00070                     partial underflow
00071                   4 if floating-point addition rounds, but not in the
00072                     IEEE style, and there is partial underflow
00073                   5 if floating-point addition rounds in the IEEE style,
00074                     and there is partial underflow
00075         ngrd    - the number of guard digits for multiplication with
00076                   truncating arithmetic.  It is
00077                   0 if floating-point arithmetic rounds, or if it
00078                     truncates and only  it  base  ibeta digits
00079                     participate in the post-normalization shift of the
00080                     floating-point significand in multiplication;
00081                   1 if floating-point arithmetic truncates and more
00082                     than  it  base  ibeta  digits participate in the
00083                     post-normalization shift of the floating-point
00084                     significand in multiplication.
00085         machep  - the largest negative integer such that
00086                   1.0+FLOAT(ibeta)**machep .NE. 1.0, except that
00087                   machep is bounded below by  -(it+3)
00088         negeps  - the largest negative integer such that
00089                   1.0-FLOAT(ibeta)**negeps .NE. 1.0, except that
00090                   negeps is bounded below by  -(it+3)
00091         iexp    - the number of bits (decimal places if ibeta = 10)
00092                   reserved for the representation of the exponent
00093                   (including the bias or sign) of a floating-point
00094                   number
00095         minexp  - the largest in magnitude negative integer such that
00096                   FLOAT(ibeta)**minexp is positive and normalized
00097         maxexp  - the smallest positive power of  BETA  that overflows
00098         eps     - the smallest positive floating-point number such
00099                   that  1.0+eps .NE. 1.0. In particular, if either
00100                   ibeta = 2  or  IRND = 0, eps = FLOAT(ibeta)**machep.
00101                   Otherwise,  eps = (FLOAT(ibeta)**machep)/2
00102         epsneg  - A small positive floating-point number such that
00103                   1.0-epsneg .NE. 1.0. In particular, if ibeta = 2
00104                   or  IRND = 0, epsneg = FLOAT(ibeta)**negeps.
00105                   Otherwise,  epsneg = (ibeta**negeps)/2.  Because
00106                   negeps is bounded below by -(it+3), epsneg may not
00107                   be the smallest number that can alter 1.0 by
00108                   subtraction.
00109         xmin    - the smallest non-vanishing normalized floating-point
00110                   power of the radix, i.e.,  xmin = FLOAT(ibeta)**minexp
00111         xmax    - the largest finite floating-point number.  In
00112                   particular  xmax = (1.0-epsneg)*FLOAT(ibeta)**maxexp
00113                   Note - on some machines  xmax  will be only the
00114                   second, or perhaps third, largest number, being
00115                   too small by 1 or 2 units in the last digit of
00116                   the significand.
00117 
00118       Latest revision - August 4, 1988
00119 
00120       Author - W. J. Cody
00121                Argonne National Laboratory
00122 
00123 */
00124 
00125 {
00126       int i,iz,j,k;
00127       int mx,itmp,nxres;
00128       volatile REAL a,b,beta,betain,one,y,z,zero;
00129       volatile REAL betah,two,t,tmp,tmpa,tmp1;
00130 
00131       (*irnd) = 1;
00132       one = (REAL)(*irnd);
00133       two = one + one;
00134       a = two;
00135       b = a;
00136       zero = 0.0e0;
00137 
00138 /*
00139   determine ibeta,beta ala malcolm
00140 */
00141 
00142       tmp = ((a+one)-a)-one;
00143 
00144       while (tmp == zero) {
00145          a = a+a;
00146          tmp = a+one;
00147          tmp1 = tmp-a;
00148          tmp = tmp1-one;
00149       }
00150 
00151       tmp = a+b;
00152       itmp = (int)(tmp-a);
00153       while (itmp == 0) {
00154          b = b+b;
00155          tmp = a+b;
00156          itmp = (int)(tmp-a);
00157       }
00158 
00159       *ibeta = itmp;
00160       beta = (REAL)(*ibeta);
00161 
00162 /*
00163   determine irnd, it
00164 */
00165 
00166       (*it) = 0;
00167       b = one;
00168       tmp = ((b+one)-b)-one;
00169 
00170       while (tmp == zero) {
00171          *it = *it+1;
00172          b = b*beta;
00173          tmp = b+one;
00174          tmp1 = tmp-b;
00175          tmp = tmp1-one;
00176       }
00177 
00178       *irnd = 0;
00179       betah = beta/two;
00180       tmp = a+betah;
00181       tmp1 = tmp-a;
00182       if (tmp1 != zero) *irnd = 1;
00183       tmpa = a+beta;
00184       tmp = tmpa+betah;
00185       if ((*irnd == 0) && (tmp-tmpa != zero)) *irnd = 2;
00186 
00187 /*
00188   determine negep, epsneg
00189 */
00190 
00191       (*negep) = (*it) + 3;
00192       betain = one / beta;
00193       a = one;
00194 
00195       for (i = 1; i<=(*negep); i++) {
00196          a = a * betain;
00197       }
00198 
00199       b = a;
00200       tmp = (one-a);
00201       tmp = tmp-one;
00202 
00203       while (tmp == zero) {
00204          a = a*beta;
00205          *negep = *negep-1;
00206          tmp1 = one-a;
00207          tmp = tmp1-one;
00208       }
00209 
00210       (*negep) = -(*negep);
00211       (*epsneg) = a;
00212 
00213 /*
00214   determine machep, eps
00215 */
00216 
00217       (*machep) = -(*it) - 3;
00218       a = b;
00219       tmp = one+a;
00220 
00221       while (tmp-one == zero) {
00222          a = a*beta;
00223          *machep = *machep+1;
00224          tmp = one+a;
00225       }
00226 
00227       *eps = a;
00228 
00229 /*
00230   determine ngrd
00231 */
00232 
00233       (*ngrd) = 0;
00234       tmp = one+*eps;
00235       tmp = tmp*one;
00236       if (((*irnd) == 0) && (tmp-one) != zero) (*ngrd) = 1;
00237 
00238 /*
00239   determine iexp, minexp, xmin
00240 
00241   loop to determine largest i such that
00242          (1/beta) ** (2**(i))
00243     does not underflow.
00244     exit from loop is signaled by an underflow.
00245 */
00246 
00247       i = 0;
00248       k = 1;
00249       z = betain;
00250       t = one+*eps;
00251       nxres = 0;
00252 
00253       for (;;) {
00254          y = z;
00255          z = y * y;
00256 
00257 /*
00258   check for underflow
00259 */
00260 
00261          a = z * one;
00262          tmp = z*t;
00263          if ((a+a == zero) || (ABS(z) > y)) break;
00264          tmp1 = tmp*betain;
00265          if (tmp1*beta == z) break;
00266          i = i + 1;
00267          k = k+k;
00268       }
00269 
00270 /*
00271   determine k such that (1/beta)**k does not underflow
00272     first set  k = 2 ** i
00273 */
00274 
00275       (*iexp) = i + 1;
00276       mx = k + k;
00277       if (*ibeta == 10) {
00278 
00279 /*
00280   for decimal machines only
00281 */
00282 
00283          (*iexp) = 2;
00284          iz = *ibeta;
00285          while (k >= iz) {
00286             iz = iz * (*ibeta);
00287             (*iexp) = (*iexp) + 1;
00288          }
00289          mx = iz + iz - 1;
00290       }
00291 
00292 /*
00293   loop to determine minexp, xmin.
00294     exit from loop is signaled by an underflow.
00295 */
00296 
00297       for (;;) {
00298          (*xmin) = y;
00299          y = y * betain;
00300          a = y * one;
00301          tmp = y*t;
00302          tmp1 = a+a;
00303          if ((tmp1 == zero) || (ABS(y) >= (*xmin))) break;
00304          k = k + 1;
00305          tmp1 = tmp*betain;
00306          tmp1 = tmp1*beta;
00307 
00308          if ((tmp1 == y) && (tmp != y)) {
00309             nxres = 3;
00310             *xmin = y;
00311             break;
00312          }
00313 
00314       }
00315 
00316       (*minexp) = -k;
00317 
00318 /*
00319   determine maxexp, xmax
00320 */
00321 
00322       if ((mx <= k+k-3) && ((*ibeta) != 10)) {
00323          mx = mx + mx;
00324          (*iexp) = (*iexp) + 1;
00325       }
00326 
00327       (*maxexp) = mx + (*minexp);
00328 
00329 /*
00330   Adjust *irnd to reflect partial underflow.
00331 */
00332 
00333       (*irnd) = (*irnd)+nxres;
00334 
00335 /*
00336   Adjust for IEEE style machines.
00337 */
00338 
00339       if ((*irnd) >= 2) (*maxexp) = (*maxexp)-2;
00340 
00341 /*
00342   adjust for machines with implicit leading bit in binary
00343     significand and machines with radix point at extreme
00344     right of significand.
00345 */
00346 
00347       i = (*maxexp) + (*minexp);
00348       if (((*ibeta) == 2) && (i == 0)) (*maxexp) = (*maxexp) - 1;
00349       if (i > 20) (*maxexp) = (*maxexp) - 1;
00350       if (a != y) (*maxexp) = (*maxexp) - 2;
00351       (*xmax) = one - (*epsneg);
00352       tmp = (*xmax)*one;
00353       if (tmp != (*xmax)) (*xmax) = one - beta * (*epsneg);
00354       (*xmax) = (*xmax) / (beta * beta * beta * (*xmin));
00355       i = (*maxexp) + (*minexp) + 3;
00356       if (i > 0) {
00357 
00358          for (j = 1; j<=i; j++ ) {
00359              if ((*ibeta) == 2) (*xmax) = (*xmax) + (*xmax);
00360              if ((*ibeta) != 2) (*xmax) = (*xmax) * beta;
00361          }
00362 
00363       }
00364 
00365     return;
00366 
00367 }
00368 
00369 #ifndef TEST
00370 
00371 F77_RET_T
00372 F77_FUNC (machar, MACHAR) (REAL *xmin, REAL *xmax, REAL *epsneg,
00373                            REAL *eps, REAL *log10_ibeta)
00374 {
00375 #if defined (_CRAY)
00376 
00377   // FIXME -- make machar work for the Cray too.
00378 
00379   int ibeta = FLT_RADIX;
00380   *xmin = DBL_MIN;
00381   *xmax = DBL_MAX;
00382   *epsneg = DBL_EPSILON;
00383   *eps = DBL_EPSILON;
00384 
00385 #else
00386 
00387   int ibeta, iexp, irnd, it, machep, maxexp, minexp, negep, ngrd;
00388 
00389   rmachar (&ibeta, &it, &irnd, &ngrd, &machep, &negep, &iexp, &minexp,
00390            &maxexp, eps, epsneg, xmin, xmax);
00391 #endif
00392 
00393   *log10_ibeta = log10 ((REAL) ibeta);
00394 
00395   F77_RETURN (0)
00396 }
00397 
00398 #else
00399 
00400 
00401 /*
00402 
00403 This program prints hardware-determined double-precision machine
00404 constants obtained from rmachar.  Dmachar is a C translation of the
00405 Fortran routine MACHAR from W. J. Cody, "MACHAR: A subroutine to
00406 dynamically determine machine parameters".  TOMS (14), 1988.
00407 
00408 Descriptions of the machine constants are given in the prologue
00409 comments in rmachar.
00410 
00411 Subprograms called
00412 
00413   rmachar
00414 
00415 Original driver: Richard Bartels, October 16, 1985
00416 
00417 Modified by: W. J. Cody
00418              July 26, 1988
00419  
00420 */
00421 int
00422 main (void)
00423 {
00424 
00425   int ibeta, iexp, irnd, it, machep, maxexp, minexp, negep, ngrd;
00426 
00427   int i;
00428 
00429   REAL eps, epsneg, xmax, xmin;
00430 
00431   union wjc
00432   {
00433     long int jj[REALSIZE];
00434     REAL xbig;
00435   } uval;
00436 
00437   rmachar  (&ibeta, &it, &irnd, &ngrd, &machep, &negep, &iexp,
00438             &minexp, &maxexp, &eps, &epsneg, &xmin, &xmax);
00439 
00440   printf (PREC);
00441   printf (" precision MACHAR constants\n");
00442   printf ("ibeta  = %d\n", ibeta);
00443   printf ("it     = %d\n", it);
00444   printf ("irnd   = %d\n", irnd);
00445   printf ("ngrd   = %d\n", ngrd);
00446   printf ("machep = %d\n", machep);
00447   printf ("negep  = %d\n", negep);
00448   printf ("iexp   = %d\n", iexp);
00449   printf ("minexp = %d\n", minexp);
00450   printf ("maxexp = %d\n", maxexp);
00451 
00452 #define DISPLAY(s, x) \
00453   do \
00454     { \
00455       uval.xbig = x ; \
00456       printf (s); \
00457       printf (" %24.16e ", (double) x) ; \
00458       for (i = 0; i < REALSIZE; i++) \
00459         printf (" %9X ", uval.jj[i]) ; \
00460       printf ("\n"); \
00461     } \
00462   while (0)
00463                         
00464   DISPLAY ("eps   ", eps);
00465   DISPLAY ("epsneg", epsneg);
00466   DISPLAY ("xmin  ", xmin);
00467   DISPLAY ("xmax  ", xmax);
00468 
00469   return 0;
00470 }
00471 
00472 #endif
SourceForge.net Logo