dolfptoa.c revision 358659
1/* 2 * dolfptoa - do the grunge work of converting an l_fp number to decimal 3 */ 4#include <config.h> 5#include <stdio.h> 6 7#include "ntp_fp.h" 8#include "lib_strbuf.h" 9#include "ntp_string.h" 10#include "ntp_stdlib.h" 11 12char * 13dolfptoa( 14 u_int32 fpi, 15 u_int32 fpv, 16 char sign, 17 short ndec, 18 int msec 19 ) 20{ 21 u_char *cp, *cpend, *cpdec; 22 int dec; 23 u_char cbuf[24]; 24 char *buf, *bp; 25 26 /* 27 * Get a string buffer before starting 28 */ 29 LIB_GETBUF(buf); 30 31 /* 32 * Zero the character buffer 33 */ 34 ZERO(cbuf); 35 36 /* 37 * Work on the integral part. This should work reasonable on 38 * all machines with 32 bit arithmetic. Please note that 32 bits 39 * can *always* be represented with at most 10 decimal digits, 40 * including a possible rounding from the fractional part. 41 */ 42 cp = cpend = cpdec = &cbuf[10]; 43 for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { 44 /* can add another digit */ 45 u_int32 digit; 46 47 digit = fpi; 48 fpi /= 10U; 49 digit -= (fpi << 3) + (fpi << 1); /* i*10 */ 50 *--cp = (u_char)digit; 51 } 52 53 /* 54 * Done that, now deal with the problem of the fraction. First 55 * determine the number of decimal places. 56 */ 57 dec = ndec; 58 if (dec < 0) 59 dec = 0; 60 if (msec) { 61 dec += 3; 62 cpdec += 3; 63 } 64 if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) 65 dec = (int)(sizeof(cbuf) - (cpend - cbuf)); 66 67 /* 68 * If there's a fraction to deal with, do so. 69 */ 70 for (/*NOP*/; dec > 0 && fpv != 0; dec--) { 71 u_int32 digit, tmph, tmpl; 72 73 /* 74 * The scheme here is to multiply the fraction 75 * (0.1234...) by ten. This moves a junk of BCD into 76 * the units part. record that and iterate. 77 * multiply by shift/add in two dwords. 78 */ 79 digit = 0; 80 M_LSHIFT(digit, fpv); 81 tmph = digit; 82 tmpl = fpv; 83 M_LSHIFT(digit, fpv); 84 M_LSHIFT(digit, fpv); 85 M_ADD(digit, fpv, tmph, tmpl); 86 *cpend++ = (u_char)digit; 87 } 88 89 /* decide whether to round or simply extend by zeros */ 90 if (dec > 0) { 91 /* only '0' digits left -- just reposition end */ 92 cpend += dec; 93 } else { 94 /* some bits remain in 'fpv'; do round */ 95 u_char *tp = cpend; 96 int carry = ((fpv & 0x80000000) != 0); 97 98 for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { 99 *--tp += 1; 100 if (*tp == 10) 101 *tp = 0; 102 else 103 carry = FALSE; 104 } 105 106 if (tp < cp) /* rounding from 999 to 1000 or similiar? */ 107 cp = tp; 108 } 109 110 /* 111 * We've now got the fraction in cbuf[], with cp pointing at 112 * the first character, cpend pointing past the last, and 113 * cpdec pointing at the first character past the decimal. 114 * Remove leading zeros, then format the number into the 115 * buffer. 116 */ 117 while (cp < cpdec && *cp == 0) 118 cp++; 119 if (cp >= cpdec) 120 cp = cpdec - 1; 121 122 bp = buf; 123 if (sign) 124 *bp++ = sign; 125 while (cp < cpend) { 126 if (cp == cpdec) 127 *bp++ = '.'; 128 *bp++ = (char)(*cp++) + '0'; 129 } 130 *bp = '\0'; 131 132 /* 133 * Done! 134 */ 135 return buf; 136} 137 138 139char * 140mfptoa( 141 u_int32 fpi, 142 u_int32 fpf, 143 short ndec 144 ) 145{ 146 int isneg; 147 148 isneg = M_ISNEG(fpi); 149 if (isneg) { 150 M_NEG(fpi, fpf); 151 } 152 153 return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE); 154} 155 156 157char * 158mfptoms( 159 u_int32 fpi, 160 u_int32 fpf, 161 short ndec 162 ) 163{ 164 int isneg; 165 166 isneg = M_ISNEG(fpi); 167 if (isneg) { 168 M_NEG(fpi, fpf); 169 } 170 171 return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE); 172} 173 174 175