/* * $ $ d t o a . c */ /*)LIBRARY */ #ifdef DOCUMENTATION title $$dtoa double to ascii conversion index double to ascii conversion usage .s char buff[]; /* space for result string */ .br char conv; /* conversion type 'e', 'f', or 'g' others default to e */ .br int bsize; /* size of buffer */ .br int dplace; /* places after the point */ .br double value; /* value to converted */ .br $$dtoa(buff, conv, bsize, dplace, value); .s description .s $$dtoa is a (temporary?) replacement for the program of the same name on the 11-SP-18 tape and described on page 5-9 of the Wizard document. The rest of this description is a copy of that. .br $$dtoa() is called by printf to convert a double precision number to ascii. The text is written to buff[]. Bsize is the maximum size of the result string; it is determined by the amount of space allocated to buff by the calling program (normally doprnt). Dplace is the number of decimal places after the decimal point. If the result is too large to fit into the space allocated to buff, digits are lost from the low end. With the buffer size of 30 bytes allocated by the modified version of doprnt() (edit b1) only rubbish digits can be lost in this way. Conv is 'e', 'f' or 'g' to define the format. .s daignostics .s None .s internal .s The program uses the following algorithm:- .br set default value of dplace .br strip off sign .br scale and compute no of leading digits .br decide if 'g' goes to 'e' or 'f' .br compute no of digits to print .br change 'f' to 'e' if insufficient space for result .br scale to range 1.0 - 10.0 and round up .br build digit string .br if not 'f' print exponent part .br print final null .s author .s Hamish Ross. .s date .s 9-Mar-85 #endif #include #define PZERO 38 /* index of 1e0 in powten[] */ #define PMAX 76 /* highest index in powten[] */ $$dtoa(buff, conv, bsize, dplace, value) char *buff; /* space for result string */ char conv; /* conversion type 'e', 'f', or 'g' others default to e */ int bsize; /* size of allocated buffer */ int dplace; /* places after the point */ double value; /* value to converted */ { extern double powten[]; double modf(), v; int i, imax, j, exp, ndigits, nlead; /* set default value of dplace */ if (dplace < 0) dplace = 6; /* strip off sign */ if (value < 0.0){ value = -value; *buff++ = '-'; } /* scale and compute no of leading digits */ if (value == 0.0) imax = PZERO; else { for (imax = PMAX; value < powten[imax] && imax > 0; imax--) { if (conv == 'f' && imax <= PZERO) break; } } exp = imax - PZERO; nlead = exp + 1; /* decide if 'g' goes to 'e' or 'f' */ if (conv == 'g') { if (nlead > 6) conv = 'e'; else conv = 'f'; } /* compute no of digits to print */ /* change 'f' to 'e' if insufficient space for result */ if (conv == 'f') { ndigits = dplace + nlead; if (ndigits + 3 > bsize) { conv = 'e'; dplace = SIGFIGS; } } if (conv != 'f') { nlead = 1; ndigits = dplace + nlead; if (ndigits > SIGFIGS) ndigits = SIGFIGS; } /* scale to range 1.0 - 10.0 and round up */ if (conv == 'e' && imax == 0 && value < powten[0]) { value *= 10.0; exp--; } value = value / powten[imax] + 0.5 * powten[PZERO - ndigits + 1]; value = modf(value, &v); if (v >= 10.0) { *buff++ = '1'; v -= 10.0; } /* build digit string */ for (i = 0; i < ndigits; i++) { if (i == nlead) *buff++ = '.'; *buff++ = (int)v + '0'; value = modf(value * 10.0, &v); } /* if not 'f' print exponent part */ if (conv != 'f'){ *buff++ = 'e'; if (exp < 0){ exp = -exp; *buff++ = '-'; } else *buff++ = '+'; j = exp/10; *buff++ = '0' + j; *buff++ = '0' + exp - 10*j; } /* print final null */ *buff++ = '\0'; return; }