📄 ldtoa.c
字号:
/* Mode 3 is "f" format. */if( mode != 3 ) ndigits -= 1;/* Mode 0 is for %.999 format, which is supposed to give a minimum length string that will convert back to the same binary value. For now, just ask for 20 digits which is enough but sometimes too many. */if( mode == 0 ) ndigits = 20;/* This sanity limit must agree with the corresponding one in etoasc, to keep straight the returned value of outexpon. */if( ndigits > NDEC ) ndigits = NDEC;etoasc( e, outbuf, ndigits, mode, ldp );s = outbuf;if( eisinf(e) || eisnan(e) ) { *decpt = 9999; goto stripspaces; }*decpt = ldp->outexpon + 1;/* Transform the string returned by etoasc into what the caller wants. *//* Look for decimal point and delete it from the string. */s = outbuf;while( *s != '\0' ) { if( *s == '.' ) goto yesdecpt; ++s; }goto nodecpt;yesdecpt:/* Delete the decimal point. */while( *s != '\0' ) { *s = *(s+1); ++s; }nodecpt:/* Back up over the exponent field. */while( *s != 'E' && s > outbuf) --s;*s = '\0';stripspaces:/* Strip leading spaces and sign. */p = outbuf;while( *p == ' ' || *p == '-') ++p;/* Find new end of string. */s = outbuf;while( (*s++ = *p++) != '\0' ) ;--s;/* Strip trailing zeros. */if( mode == 2 ) k = 1;else if( ndigits > ldp->outexpon ) k = ndigits;else k = ldp->outexpon;while( *(s-1) == '0' && ((s - outbuf) > k)) *(--s) = '\0';/* In f format, flush small off-scale values to zero. Rounding has been taken care of by etoasc. */if( mode == 3 && ((ndigits + ldp->outexpon) < 0)) { s = outbuf; *s = '\0'; *decpt = 0; }/* reentrancy addition to use mprec storage pool *//* we want to have enough space to hold the formatted result */if (mode == 3) /* f format, account for sign + dec digits + decpt + frac */ i = *decpt + orig_ndigits + 3;else /* account for sign + max precision digs + E + exp sign + exponent */ i = orig_ndigits + MAX_EXP_DIGITS + 4;j = sizeof (__ULong);for (_REENT_MP_RESULT_K(ptr) = 0; sizeof (_Bigint) - sizeof (__ULong) + j <= i; j <<= 1) _REENT_MP_RESULT_K(ptr)++;_REENT_MP_RESULT(ptr) = Balloc (ptr, _REENT_MP_RESULT_K(ptr));/* Copy from internal temporary buffer to permanent buffer. */outstr = (char *)_REENT_MP_RESULT(ptr);strcpy (outstr, outbuf);if( rve ) *rve = outstr + (s - outbuf);return outstr;}/* Routine used to tell if long double is NaN or Infinity or regular number. Returns: 0 = regular number 1 = Nan 2 = Infinity*/int_ldcheck (long double *d){unsigned short e[NI];LDPARMS rnd;LDPARMS *ldp = &rnd;rnd.rlast = -1;rnd.rndprc = NBITS;union uconv du;du.d = *d;#if LDBL_MANT_DIG == 24e24toe( &du.pe, e, ldp );#elif LDBL_MANT_DIG == 53e53toe( &du.pe, e, ldp );#elif LDBL_MANT_DIG == 64e64toe( &du.pe, e, ldp );#elsee113toe( &du.pe, e, ldp );#endifif( (e[NE-1] & 0x7fff) == 0x7fff ) {#ifdef NANS if( eisnan(e) ) return( 1 );#endif return( 2 ); }else return( 0 );} /* _ldcheck */static void etoasc(short unsigned int *x, char *string, int ndigits, int outformat, LDPARMS *ldp){long digit;unsigned short y[NI], t[NI], u[NI], w[NI];unsigned short *p, *r, *ten;unsigned short sign;int i, j, k, expon, rndsav, ndigs;char *s, *ss;unsigned short m;unsigned short *equot = ldp->equot;ndigs = ndigits;rndsav = ldp->rndprc;#ifdef NANSif( eisnan(x) ) { sprintf( string, " NaN " ); expon = 9999; goto bxit; }#endifldp->rndprc = NBITS; /* set to full precision */emov( x, y ); /* retain external format */if( y[NE-1] & 0x8000 ) { sign = 0xffff; y[NE-1] &= 0x7fff; }else { sign = 0; }expon = 0;ten = &etens[NTEN][0];emov( eone, t );/* Test for zero exponent */if( y[NE-1] == 0 ) { for( k=0; k<NE-1; k++ ) { if( y[k] != 0 ) goto tnzro; /* denormalized number */ } goto isone; /* legal all zeros */ }tnzro:/* Test for infinity. */if( y[NE-1] == 0x7fff ) { if( sign ) sprintf( string, " -Infinity " ); else sprintf( string, " Infinity " ); expon = 9999; goto bxit; }/* Test for exponent nonzero but significand denormalized. * This is an error condition. */if( (y[NE-1] != 0) && ((y[NE-2] & 0x8000) == 0) ) { mtherr( "etoasc", DOMAIN ); sprintf( string, "NaN" ); expon = 9999; goto bxit; }/* Compare to 1.0 */i = ecmp( eone, y );if( i == 0 ) goto isone;if( i < 0 ) { /* Number is greater than 1 *//* Convert significand to an integer and strip trailing decimal zeros. */ emov( y, u ); u[NE-1] = EXONE + NBITS - 1; p = &etens[NTEN-4][0]; m = 16;do { ediv( p, u, t, ldp ); efloor( t, w, ldp ); for( j=0; j<NE-1; j++ ) { if( t[j] != w[j] ) goto noint; } emov( t, u ); expon += (int )m;noint: p += NE; m >>= 1; }while( m != 0 );/* Rescale from integer significand */ u[NE-1] += y[NE-1] - (unsigned int )(EXONE + NBITS - 1); emov( u, y );/* Find power of 10 */ emov( eone, t ); m = MAXP; p = &etens[0][0]; while( ecmp( ten, u ) <= 0 ) { if( ecmp( p, u ) <= 0 ) { ediv( p, u, u, ldp ); emul( p, t, t, ldp ); expon += (int )m; } m >>= 1; if( m == 0 ) break; p += NE; } }else { /* Number is less than 1.0 *//* Pad significand with trailing decimal zeros. */ if( y[NE-1] == 0 ) { while( (y[NE-2] & 0x8000) == 0 ) { emul( ten, y, y, ldp ); expon -= 1; } } else { emovi( y, w ); for( i=0; i<NDEC+1; i++ ) { if( (w[NI-1] & 0x7) != 0 ) break;/* multiply by 10 */ emovz( w, u ); eshdn1( u ); eshdn1( u ); eaddm( w, u ); u[1] += 3; while( u[2] != 0 ) { eshdn1(u); u[1] += 1; } if( u[NI-1] != 0 ) break; if( eone[NE-1] <= u[1] ) break; emovz( u, w ); expon -= 1; } emovo( w, y, ldp ); } k = -MAXP; p = &emtens[0][0]; r = &etens[0][0]; emov( y, w ); emov( eone, t ); while( ecmp( eone, w ) > 0 ) { if( ecmp( p, w ) >= 0 ) { emul( r, w, w, ldp ); emul( r, t, t, ldp ); expon += k; } k /= 2; if( k == 0 ) break; p += NE; r += NE; } ediv( t, eone, t, ldp ); }isone:/* Find the first (leading) digit. */emovi( t, w );emovz( w, t );emovi( y, w );emovz( w, y );eiremain( t, y, ldp );digit = equot[NI-1];while( (digit == 0) && (ecmp(y,ezero) != 0) ) { eshup1( y ); emovz( y, u ); eshup1( u ); eshup1( u ); eaddm( u, y ); eiremain( t, y, ldp ); digit = equot[NI-1]; expon -= 1; }s = string;if( sign ) *s++ = '-';else *s++ = ' ';/* Examine number of digits requested by caller. */if( outformat == 3 ) ndigs += expon;/*else if( ndigs < 0 ) ndigs = 0;*/if( ndigs > NDEC ) ndigs = NDEC;if( digit == 10 ) { *s++ = '1'; *s++ = '.'; if( ndigs > 0 ) { *s++ = '0'; ndigs -= 1; } expon += 1; if( ndigs < 0 ) { ss = s; goto doexp; } }else { *s++ = (char )digit + '0'; *s++ = '.'; }/* Generate digits after the decimal point. */for( k=0; k<=ndigs; k++ ) {/* multiply current number by 10, without normalizing */ eshup1( y ); emovz( y, u ); eshup1( u ); eshup1( u ); eaddm( u, y ); eiremain( t, y, ldp ); *s++ = (char )equot[NI-1] + '0'; }digit = equot[NI-1];--s;ss = s;/* round off the ASCII string */if( digit > 4 ) {/* Test for critical rounding case in ASCII output. */ if( digit == 5 ) { emovo( y, t, ldp ); if( ecmp(t,ezero) != 0 ) goto roun; /* round to nearest */ if( (*(s-1) & 1) == 0 ) goto doexp; /* round to even */ }/* Round up and propagate carry-outs */roun: --s; k = *s & 0x7f;/* Carry out to most significant digit? */ if( ndigs < 0 ) { /* This will print like "1E-6". */ *s = '1'; expon += 1; goto doexp; } else if( k == '.' ) { --s; k = *s; k += 1; *s = (char )k;/* Most significant digit carries to 10? */ if( k > '9' ) { expon += 1; *s = '1'; } goto doexp; }/* Round up and carry out from less significant digits */ k += 1; *s = (char )k; if( k > '9' ) { *s = '0'; goto roun; } }doexp:#ifdef __GO32__if( expon >= 0 ) sprintf( ss, "e+%02d", expon );else sprintf( ss, "e-%02d", -expon );#else sprintf( ss, "E%d", expon );#endifbxit:ldp->rndprc = rndsav;ldp->outexpon = expon;}/*; ASCTOQ; ASCTOQ.MAC LATEST REV: 11 JAN 84; SLM, 3 JAN 78;; Convert ASCII string to quadruple precision floating point;; Numeric input is free field decimal number; with max of 15 digits with or without ; decimal point entered as ASCII from teletype.; Entering E after the number followed by a second; number causes the second number to be interpreted; as a power of 10 to be multiplied by the first number; (i.e., "scientific" notation).;; Usage:; asctoq( string, q );*/long double _strtold (char *s, char **se){ union uconv x; LDPARMS rnd; LDPARMS *ldp = &rnd; int lenldstr; rnd.rlast = -1; rnd.rndprc = NBITS; lenldstr = asctoeg( s, &x.pe, LDBL_MANT_DIG, ldp ); if (se) *se = s + lenldstr; return x.d;}#define REASONABLE_LEN 200static intasctoeg(char *ss, short unsigned int *y, int oprec, LDPARMS *ldp){unsigned short yy[NI], xt[NI], tt[NI];int esign, decflg, sgnflg, nexp, exp, prec, lost;int k, trail, c, rndsav;long lexp;unsigned short nsign, *p;char *sp, *s, *lstr;int lenldstr;int mflag = 0;char tmpstr[REASONABLE_LEN];/* Copy the input string. */c = strlen (ss) + 2;if (c <= REASONABLE_LEN) lstr = tmpstr;else { lstr = (char *) calloc (c, 1); mflag = 1; }s = ss;lenldstr = 0;while( *s == ' ' ) /* skip leading spaces */ { ++s; ++lenldstr; }sp = lstr;for( k=0; k<c; k++ ) { if( (*sp++ = *s++) == '\0' ) break; }*sp = '\0';s = lstr;rndsav = ldp->rndprc;ldp->rndprc = NBITS; /* Set to full precision */lost = 0;nsign = 0;decflg = 0;sgnflg = 0;nexp = 0;exp = 0;prec = 0;ecleaz( yy );trail = 0;nxtcom:k = *s - '0';if( (k >= 0) && (k <= 9) ) {/* Ignore leading zeros */ if( (prec == 0) && (decflg == 0) && (k == 0) ) goto donchr;/* Identify and strip trailing zeros after the decimal point. */ if( (trail == 0) && (decflg != 0) ) { sp = s; while( (*sp >= '0') && (*sp <= '9') ) ++sp;/* Check for syntax error */ c = *sp & 0x7f; if( (c != 'e') && (c != 'E') && (c != '\0') && (c != '\n') && (c != '\r') && (c != ' ') && (c != ',') ) goto error; --sp; while( *sp == '0' ) *sp-- = 'z'; trail = 1; if( *s == 'z' ) goto donchr; }/* If enough digits were given to more than fill up the yy register, * continuing until overflow into the high guard word yy[2] * guarantees that there will be a roundoff bit at the top * of the low guard word after normalization. */ if( yy[2] == 0 ) { if( decflg ) nexp += 1; /* count digits after decimal point */ eshup1( yy ); /* multiply current number by 10 */ emovz( yy, xt ); eshup1( xt ); eshup1( xt ); eaddm( xt, yy ); ecleaz( xt ); xt[NI-2] = (unsigned short )k; eaddm( xt, yy ); } else { /* Mark any lost non-zero digit. */ lost |= k; /* Count lost digits before the decimal point. */ if (decflg == 0) nexp -= 1; } prec += 1; goto donchr; }switch( *s ) { case 'z': break; case 'E': case 'e': goto expnt; case '.': /* decimal point */ if( decflg ) goto error; ++decflg; break; case '-': nsign = 0xffff; if( sgnflg ) goto error; ++sgnflg; break; case '+': if( sgnflg ) goto error; ++sgnflg; break; case ',': case ' ': case '\0': case '\n': case '\r': goto daldone; case 'i': case 'I': goto infinite; default: error:#ifdef NANS enan( yy, NI*16 );#else mtherr( "asctoe", DOMAIN ); ecleaz(yy);#endif goto aexit; }donchr:++s;goto nxtcom;/* Exponent interpretation */expnt:esign = 1;exp = 0;++s;/* check for + or - */if( *s == '-' ) { esign = -1; ++s; }if( *s == '+' ) ++s;while( (*s >= '0') && (*s <= '9') ) { exp *= 10; exp += *s++ - '0'; if (exp > 4977) { if (esign < 0) goto zero; else goto infinite; } }if( esign < 0 ) exp = -exp;if( exp > 4932 ) {infinite: ecleaz(yy); yy[E] = 0x7fff; /* infinity */ goto aexit; }if( exp < -4977 ) {zero: ecleaz(yy); got
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -