home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 9.ddi / IOSTRSR1.ZIP / OSTFLOAT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  12.8 KB  |  414 lines

  1. /*[]------------------------------------------------------------[]*/
  2. /*|                                                              |*/
  3. /*|     ostfloat.cpp                                             |*/
  4. /*|                                                              |*/
  5. /*|     Class ostream                                            |*/
  6. /*|          ostream& ostream::operator<< ( long double )        |*/
  7. /*|                                                              |*/
  8. /*[]------------------------------------------------------------[]*/
  9.  
  10. /*
  11.  *      C/C++ Run Time Library - Version 5.0
  12.  *
  13.  *      Copyright (c) 1990, 1992 by Borland International
  14.  *      All Rights Reserved.
  15.  *
  16.  */
  17.  
  18. /*
  19.     This code assumes the IEEE Standard 754-1985 model of floating-point
  20.     numbers, but makes no assumptions about the details of the floating-point
  21.     representation.  There are several IEEE kinds (classes) of number.
  22.     Positive or Negative Infinity result on overflow, and propagate
  23.     as a mathematical infinity does.  Overflow and underflow may or may not
  24.     produce a signal (interrupt).  Operations on infinities may or may not
  25.     produce a signal.
  26.     An undefined operation, such as (0.0 / 0.0) or (0.0 * Infinity),
  27.     produces a special value called Not-A-Number, or NaN.
  28.     Any operation on a NaN results in a NaN.  Production of or operations on
  29.     a NaN may or may not produce a signal (interrupt).
  30.     When a result is smaller in magnitude than the smallest standard value
  31.     but is not zero, it may be represented as a Denormalized number.
  32.     Operations on denormalized numbers may or may not produce a signal.
  33.  
  34.     The IEEE standard recommends that any implementation supply certain
  35.     auxiliary functions to help in working with special values.  These
  36.     recommended functions are in a header file called <fakeieee.h>.
  37.  
  38.     This code uses the following IEEE functions:
  39.     // return the kind of number
  40.     int fpclass( long double );
  41.  
  42.     // return the first value with the sign of the second,
  43.     // even if one is Infinity or NaN, which would otherwise be
  44.     // an illegal operation
  45.     long double fpcopysign( long double, long double );
  46.  
  47.     // return true if -INFINITY < parameter < +INFINITY
  48.     int fpfinite( long double );
  49.  
  50.     // return true if parameter is a NaN
  51.     int fpisnan( long double );
  52.  
  53.     In addition, we generate special strings for +Infinity, -Infinity,
  54.     and NotANumber.  You may wish to generate other strings, or just
  55.     set Infinities to HUGE_VAL and emit them normally.  It is not
  56.     obvious what to do about NaN's in that case.
  57.  
  58.     If your system does not have an <ieee.h> or equivalent header, or
  59.     if your floating-point system does not fit this model, you may as
  60.     an expedient define the macro name _NOIEEE_ immediately below, and
  61.     use a simplified header "fakeieee.h" supplied with this package.
  62.     You will later want to go through the code to provide any needed
  63.     functionality depending on your floating-point model.
  64.  
  65.     Long doubles are not directly supported by this package.  The
  66.     modifications to support them should be obvious and straightforward.
  67.  
  68.     NOTES:
  69.     1.  Function "round" below contains a rounding table which must
  70.     have as many entries as there are significant decimal digits in
  71.     the floating-point representation.  IEEE double-precision provides
  72.     about 16 significant decimal digits.
  73.     2.  Function "eout" below assumes that the maximum exponent of 10
  74.     which can be represented is no bigger than 999.  This may not be
  75.     true for long doubles, and provision for extra digits will be
  76.     needed.
  77.  
  78.  
  79.     This code has now been modified to use type long double exclusively,
  80.     under the assumption that the math chips and the software floating-
  81.     point library all convert all floats and doubles to long double
  82.     internally.  It makes more sense to do this conversion once on input
  83.     and once on output rather than multiple times.
  84. */
  85.  
  86. #define _NOIEEE_
  87.  
  88. #include <ioconfig.h>
  89. #include <iostream.h>
  90. #include <string.h>
  91. #include <math.h>
  92.  
  93. #ifdef _NOIEEE_
  94. #   include "fakeieee.h"
  95. #else
  96. #   include <ieee.h>
  97. #endif
  98.  
  99. static char Infinity[]    = "[+Infinity]";
  100. static char NegInfinity[] = "[-Infinity]";
  101. static char NotANumber[]  = "[NotANumber]";
  102.  
  103. // structure used to pass around the current status of the value
  104.  
  105. struct float_data {
  106.     int exp;        // the power of 10
  107.     long double remain; // normalized range [1.0, 10.0), unprinted digits
  108.     int is_neg;     // is this a negative value
  109.     int is_zero;    // is value zero
  110.     int showpoint;  // do we force display of decimal point
  111.     int precision;  // precision to display (number of digits)
  112.     int expchar;    // 'e' or 'E' in scientific format
  113. };
  114.  
  115.  
  116. /*
  117.  * Funny version of frexp() for long doubles which just returns
  118.  * the exponent.  We don't have long double format published in any
  119.  * header, so we just use non-portable magic code to do the job.
  120.  * Some day we may have a real library version of frexpl(), which
  121.  * should then be used.
  122.  */
  123.  
  124. static int lfrexp(long double x)
  125. {
  126.     // get last 15 bits of the long double
  127.     int res = (((unsigned int*) &x)[4]) & 0x7FFF;
  128.     return (res == 0) ? 0 : res - 0x3FFF;
  129. }
  130.  
  131. //  Normalize representation of floating value as signed magnitude in
  132. //  range [1.0, 10.0) times 10^exp, or as 0.0
  133.  
  134. static void normalize( long double val, float_data& eval )
  135. {
  136.     eval.is_neg = 0;
  137.     eval.is_zero = 0;
  138.     eval.exp = 0;
  139.  
  140.     switch( fpclass(val) )
  141.         {
  142.         case FPSIGNAN:
  143.         case FPQUIETNAN:
  144.             break;              // cannot process NaN's
  145.  
  146.         case FPNEGINF:
  147.             eval.is_neg = 1;
  148.             val = fpcopysign(val, 1.0); // make into positive infinity
  149.             // fall through
  150.  
  151.         case FPPOSINF:
  152.             break;
  153.  
  154.         case FPNEGZERO:
  155.             eval.is_neg = 1;
  156.             val = 0.0;          // make into non-negative zero
  157.             // fall through
  158.  
  159.         case FPPOSZERO:
  160.             eval.is_zero = 1;
  161.             break;
  162.  
  163.         case FPNEG:
  164.         case FPNEGDENOR:
  165.             eval.is_neg = 1;
  166.             val = -val;         // make positive
  167.             // fall through
  168.  
  169.         case FPPOSDENOR:
  170.         case FPPOS:
  171.         // processing for non-special values
  172.  
  173.             // this calculation is not exact, but we fix it up later
  174.             int exp = lfrexp(val);             // get exponent base 2
  175.             exp = (int) (((long) exp * 2466L) / 8192); // approx exponent base 10
  176.             eval.exp = exp;
  177.  
  178.             if( exp != 0 )
  179.                 {
  180.                 int neg = 0;
  181.                 if( exp < 0 )
  182.                     {
  183.                     exp = -exp;
  184.                     neg = 1;
  185.                     }
  186.                 long double power = 1.0;
  187.                 long double temp = 10.0;
  188.                 do  {
  189.                     while( exp != 0  &&  (exp & 1) == 0 )
  190.                         {
  191.                         temp *= temp;
  192.                         exp >>= 1;
  193.                         }
  194.                     power *= temp;
  195.                     exp--;
  196.                     } while( exp != 0 );
  197.                 if( neg )
  198.                     val *= power;
  199.                 else
  200.                     val /= power;
  201.                 }
  202.  
  203.             // fix up if out of range (we know it can't be >= 10.0)
  204.             if( val < 1.0 )
  205.                 {
  206.                 val *= 10.0L;
  207.                 eval.exp -= 1;
  208.                 }
  209.             break;
  210.         }
  211.  
  212.     eval.remain = val;
  213. }
  214.  
  215.  
  216. // Return the ASCII representation of the next digit of the value,
  217. // adjusting remainder.
  218.  
  219. static char next_digit( float_data& eval )
  220. {
  221.     int digit;
  222.  
  223.     digit = (int) eval.remain;
  224.     eval.remain = 10.0L * (eval.remain - (long double) digit);
  225.     return digit + '0';
  226. }
  227.  
  228.  
  229. // Generate ASCII digits for value in float_data.
  230. // Return pointer to the end of the string.
  231.  
  232. static char* flt_out( float_data& eval, char *pt )
  233. {
  234.     int count, exp;
  235. #pragma -eff
  236.     if( fpisnan(eval.remain) )
  237.         {
  238.         strcpy(pt, NotANumber);
  239.         pt += strlen(pt);
  240.         }
  241. #pragma .eff
  242.  
  243.     else if( ! fpfinite(eval.remain) )
  244.         {
  245.         if( eval.is_neg )
  246.             strcpy(pt, NegInfinity);
  247.         else
  248.             strcpy(pt, Infinity);
  249.         pt += strlen(pt);
  250.         }
  251.     else
  252.         {
  253.         // integer portion
  254.         exp = eval.exp + 1; // add 1 to make subsequent tests cheaper
  255.         if( exp <= 0 )
  256.             *(pt++) = '0';
  257.         else
  258.             for( ;  exp > 0;  exp-- )
  259.                 *(pt++) = next_digit(eval);
  260.  
  261.         // possible decimal point
  262.         if( eval.precision  ||  eval.showpoint )
  263.             *(pt++) = '.';
  264.  
  265.         // fraction portion
  266.         for( count = eval.precision;  count > 0;  count-- )
  267.             {
  268.             if( exp < 0 )
  269.                 {
  270.                 *(pt++) = '0';
  271.                 exp++;
  272.                 }
  273.             else
  274.                 *(pt++) = next_digit(eval);
  275.             }
  276.  
  277.         // maybe strip trailing fractional zeros
  278.         if( eval.precision  &&  ! eval.showpoint )
  279.             {
  280.             while( pt[-1] == '0' )
  281.                 --pt;
  282.             if( pt[-1] == '.' )
  283.                 --pt;   // don't leave a bare decimal point
  284.             }
  285.  
  286.         *pt = '\0';
  287.         }
  288.  
  289.     return pt;
  290. }
  291.  
  292.  
  293. // "digits" = normalized fraction digits affected by rounding.
  294.  
  295. static void round( float_data& eval, int digits )
  296. {
  297.     // roundamt[n] == 1/2 of nth digit
  298.     const int sigdig = 20;  // see note in introduction
  299.     static long double roundamt[sigdig+1] =
  300.     { 5.0e-1,  5.0e-2,  5.0e-3,  5.0e-4,  5.0e-5,  5.0e-6,
  301.       5.0e-7,  5.0e-8,  5.0e-9,  5.0e-10, 5.0e-11, 5.0e-12,
  302.       5.0e-13, 5.0e-14, 5.0e-15, 5.0e-16, 5.0e-17, 5.0e-18,
  303.       5.0e-19, 5.0e-20, 5.0e-21
  304.     };
  305.  
  306.     switch( fpclass(eval.remain) )
  307.         {
  308.         case FPSIGNAN:
  309.         case FPQUIETNAN:
  310.         case FPNEGINF:
  311.         case FPNEGZERO:
  312.         case FPPOSZERO:
  313.         case FPPOSINF:
  314.             break;      // no rounding needed or possible
  315.  
  316.         default:      // finite value may require rounding
  317.             if(digits >= 0 && digits <= sigdig)
  318.                 {
  319.                 eval.remain += roundamt[digits];
  320.                 if( eval.remain >= 10.0L )
  321.                     {
  322.                     eval.remain /= 10.0L;
  323.                     eval.exp++;
  324.                     }
  325.                 }
  326.             break;
  327.         }
  328. }
  329.  
  330.  
  331. // generate a number in scientific format
  332. // if values greater than 10^999 are possible, see note in introduction
  333.  
  334. static void eout( float_data& eval, char* buf )
  335. {
  336.     // rounding can affect exponent, so do it first
  337.     round(eval, eval.precision);
  338.  
  339.     // save exponent data
  340.     int negexp = 0;     // is exponent negative
  341.     int exp = eval.exp;     // absolute value of exponent
  342.     if( exp < 0 )
  343.         {
  344.         negexp = 1;
  345.         exp = -exp;
  346.         }
  347.  
  348.     // generate digits field
  349.     eval.exp = 0;   // for flt_out
  350.     char* pt = flt_out(eval, buf);
  351.  
  352.     if( fpfinite(eval.remain) )
  353.         {
  354.         // generate exponent field
  355.         *(pt++) = eval.expchar;
  356.         if( negexp )
  357.             *(pt++) = '-'; // always a sign
  358.         else
  359.             *(pt++) = '+';
  360.         if(exp >= 100)
  361.             {
  362.             if (exp >= 1000)
  363.                 {
  364.                 *(pt++) = '0' + exp / 1000; // fourth digit needed
  365.                 exp %= 1000;
  366.                 }
  367.             *(pt++) = '0' + exp / 100;      // third digit needed
  368.             exp %= 100;
  369.             }
  370.         *(pt++) = '0' + exp / 10;           // at least two digits
  371.         *(pt++) = '0' + exp % 10;
  372.         *(pt++) = '\0';
  373.         }
  374. }
  375.  
  376.  
  377. ostream _FAR & ostream::operator<< (long double d)
  378. {
  379.     float_data eval;
  380.     char buf[60];   // big enough for any floating result
  381.  
  382.     normalize(d, eval);
  383.     eval.expchar = (flags() & ios::uppercase) ? 'E' : 'e';
  384.     eval.precision = precision();
  385.     if( eval.precision <= 0 )
  386.         eval.precision = 6; // default value for precision
  387.     eval.showpoint = (flags() & ios::showpoint) != 0;
  388.  
  389.     if( flags() & ios::fixed )
  390.         {
  391.         round(eval, eval.exp + eval.precision);
  392.         flt_out(eval, buf);
  393.         }
  394.     else if( flags() & ios::scientific )
  395.         eout(eval, buf);
  396.     else if( eval.exp < -4  ||  eval.precision < eval.exp )
  397.         eout(eval, buf);    // default to scientific
  398.     else
  399.         {          // default to fixed
  400.         round(eval, eval.exp + eval.precision);
  401.         flt_out(eval, buf);
  402.         }
  403.  
  404.     char* prefix = 0;
  405.     if( eval.is_neg )
  406.         prefix = "-";
  407.     else if( ! eval.is_zero  &&  (flags() & ios::showpos) )
  408.         prefix = "+";
  409.  
  410.     // now we have a formatted string for output, to be possibly padded
  411.     outstr(buf, prefix);
  412.     return *this;
  413. }
  414.