home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c065 / 2.ddi / CLIB2.ZIP / ISTREAMF.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  6.7 KB  |  250 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - istreamf.cpp
  3.  * Class istream member functions for extracting floating types
  4.  *-----------------------------------------------------------------------*/
  5.  
  6. /*[]------------------------------------------------------------[]*/
  7. /*|                                                              |*/
  8. /*|     Turbo C++ Run Time Library - Version 1.0                 |*/
  9. /*|                                                              |*/
  10. /*|                                                              |*/
  11. /*|     Copyright (c) 1990 by Borland International              |*/
  12. /*|     All Rights Reserved.                                     |*/
  13. /*|                                                              |*/
  14. /*[]------------------------------------------------------------[]*/
  15.  
  16. /*
  17.  * If you have an optimized strtod() routine (or atof() or equivalent),
  18.  * you may wish to extract characters into a local string and call
  19.  * strtod() with that string instead of using the code given here.
  20.  *
  21.  * We take care to avoid floating-point overflow and underflow during all
  22.  * calculations and set errno to ERANGE on overflow and underflow, but
  23.  * we do not raise any error signals.
  24.  * You can speed up the code by removing the checks if they don't matter
  25.  * in your system.
  26.  *
  27.  * Type long double is not supported explicitly, but adding code to
  28.  * support long doubles should be obvious and straightforward.
  29.  *
  30.  * This code has now been modified to use type long double exclusively,
  31.  * under the assumption that the math chips and the software floating-
  32.  * point library all convert all floats and doubles to long double
  33.  * internally.  It makes more sense to do this conversion once on input
  34.  * and once on output rather than multiple times.
  35.  */
  36.  
  37. #include <iostream.h>
  38. #include <ctype.h>
  39. #include <float.h>    // for characteristics of floating types
  40. #include <math.h>       // for HUGE_VAL
  41. #include <errno.h>    // for reporting range errors
  42.  
  43.  
  44.  
  45. /*
  46.  * We assume that extracting a long double and casting to float is not
  47.  * significantly more expensive than working only with floats.
  48.  */
  49. istream& istream::operator>> (float& f)
  50. {
  51.     long double x;
  52.  
  53.     *this >> x;        // extract the value
  54.     if( ! fail() ) {    // value returned only if no failure
  55.     if( x < -FLT_MAX ) {
  56.         errno = ERANGE;
  57.         f = -FLT_MAX;
  58.     }
  59.     else if( FLT_MAX < x ) {
  60.         errno = ERANGE;
  61.         f = FLT_MAX;
  62.     }
  63.     else
  64.         f = float(x);
  65.     }
  66.     return *this;
  67. }
  68.  
  69.  
  70. /*
  71.  * We assume that extracting a long double and casting to double is not
  72.  * significantly more expensive than working only with doubles.
  73.  */
  74. istream& istream::operator>> (double& d)
  75. {
  76.     long double x;
  77.  
  78.     *this >> x;        // extract the value
  79.     if( ! fail() ) {    // value returned only if no failure
  80.     if( x < -DBL_MAX ) {
  81.         errno = ERANGE;
  82.         x = -DBL_MAX;
  83.     }
  84.     else if( DBL_MAX < x ) {
  85.         errno = ERANGE;
  86.         x = DBL_MAX;
  87.     }
  88.     else
  89.         d = double(x);
  90.     }
  91.     return *this;
  92. }
  93.  
  94.  
  95. /*
  96.  * The following defines are for type long double.
  97.  * If you want to do float or long separately,
  98.  * you will need to supply the appropriate values
  99.  */
  100. #define Dbigexp 49320L        // much bigger than any power 10 exponent
  101. #define Dmaxint 493200L        // (10*Dbigexp)
  102. #define Dfixexp 2466L        // about max_10_exp / 2
  103. #define Dfixval 1.0e2466    // 10 ** Dfixexp
  104.  
  105.  
  106. istream& istream::operator>> (long double& val)
  107. {
  108.     if( ipfx0() ) {        // verify file state and possibly skip white
  109.  
  110.     int c;            // current input character
  111.     int negval;        // entire value is negative
  112.     int negexp;        // exponent is negative
  113.     long exp;        // accumulated exponent
  114.     int formok;        // floating-point number format is valid
  115.  
  116.     formok = 0;        // until proven otherwise
  117.     c = bp->sgetc();    // look at first character
  118.  
  119.     // get leading sign
  120.     negval = c == '-';
  121.     if( c == '+'  ||  negval )
  122.         c = bp->snextc();
  123.     else if( c == EOF )
  124.         setstate(ios::badbit);    // no characters extracted
  125.  
  126.     // scan off digits up to decimal point
  127.     val = 0.0;
  128.     if( isdigit(c) ) {
  129.         formok = 1;
  130.         do {
  131.         c -= '0';
  132.         val = 10.0 * val + c;
  133.         c = bp->snextc();
  134.         } while( isdigit(c) );
  135.     }
  136.  
  137.     // scan off fractional digits, keeping count
  138.     exp = 0;
  139.     if( c == '.' ) {
  140.         c = bp->snextc();
  141.         if( isdigit(c) ) {
  142.         formok = 1;
  143.         do {
  144.             c -= '0';
  145.             val = 10.0 * val + c;
  146.             --exp;
  147.             c = bp->snextc();
  148.         } while( isdigit(c) );
  149.         }
  150.     }
  151.  
  152.     // look for possibly-signed exponent
  153.     if( formok  &&  (c == 'e'  ||  c == 'E') ) {
  154.         c = bp->snextc();
  155.         formok = isdigit(c)  ||  c == '+'  ||  c == '-';
  156.  
  157.         long givenexp = 0;    // exponent given in E... part of number
  158.         if( ! formok ) val = 0.0;
  159.         else {
  160.         // convert possibly-signed exponent
  161.         negexp = c == '-';    // here we mean the given exponent
  162.         if( c == '+'  ||  negexp )
  163.             c = bp->snextc();
  164.         formok = isdigit(c);
  165.         if( ! formok ) val = 0.0;
  166.         else {
  167.             do {
  168.             if( givenexp < Dbigexp ) {
  169.                 c -= '0';
  170.                 givenexp = 10 * givenexp + c;
  171.             }
  172.             c = bp->snextc();
  173.             } while( isdigit(c) );
  174.         }
  175.         }
  176.  
  177.         // adjust exponent by given exponent, watching for overflow
  178.         if( negexp ) {
  179.         if( givenexp - Dmaxint < exp ) exp -= givenexp;
  180.         else exp = - Dmaxint;
  181.         }
  182.         else {
  183.         if( Dmaxint - givenexp > exp ) exp += givenexp;
  184.         else exp = Dmaxint;
  185.         }
  186.     }
  187.  
  188.     // try to salvage some underflow
  189.     if( exp <= DBL_MIN_10_EXP ) {
  190.         val /= Dfixval;
  191.         exp += Dfixexp;;
  192.     }
  193.  
  194.     // final calculation
  195.     if( exp < DBL_MIN_10_EXP ) {
  196.         val = 0.0;
  197.         errno = ERANGE;
  198.     }
  199.     else if( exp > DBL_MAX_10_EXP )  {
  200.         val = HUGE_VAL;
  201.         errno = ERANGE;
  202.     }
  203.     else if( formok ) {
  204.         int overflow = 0;        // did overflow occur
  205.         double adjust = 1.0;    // amount to adjust because of exponent
  206.         double power = 10.0;    // used in building adjust
  207.         negexp = exp < 0;        // negexp now refers to net exponent
  208.         if( negexp ) exp = -exp;    // exp is now absolute value
  209.  
  210.         // compute val * (10 ** exp)
  211.         while( exp > 0 ) {
  212.         if( exp & 1 ) {
  213.             if( DBL_MAX / adjust >= power ) adjust *= power;
  214.             else overflow = 1;
  215.         }
  216.         exp >>= 1;
  217.         if( exp > 0 ) {
  218.             if( DBL_MAX / power >= power ) power *= power;
  219.             else overflow = 1;
  220.         }
  221.         }
  222.  
  223.         if( ! overflow ) {
  224.         if( adjust != 1.0 ) {
  225.             if( negexp ) val /= adjust;
  226.             else if( val <= 1.0 ) val *= adjust;
  227.             else if( DBL_MAX / val >= adjust ) val *= adjust;
  228.             else overflow = 1;
  229.         }
  230.         }
  231.         if( overflow ) {
  232.         if( negexp ) val = 0.0;
  233.         else val = HUGE_VAL;
  234.         errno = ERANGE;
  235.         }
  236.     }
  237.  
  238.     if( formok ) {
  239.         if( negval )
  240.         val = -val;    // adjust the sign
  241.     }
  242.     else if( c == EOF)
  243.         setstate(ios::eofbit | ios::failbit);
  244.     else
  245.         setstate(ios::failbit);
  246.     }
  247.  
  248.     return *this;
  249. }
  250.