dolfptoa.c revision 293896
1193323Sed/* 2193323Sed * dolfptoa - do the grunge work of converting an l_fp number to decimal 3193323Sed */ 4193323Sed#include <config.h> 5193323Sed#include <stdio.h> 6193323Sed 7193323Sed#include "ntp_fp.h" 8193323Sed#include "lib_strbuf.h" 9193323Sed#include "ntp_string.h" 10193323Sed#include "ntp_stdlib.h" 11193323Sed 12193323Sedchar * 13193323Seddolfptoa( 14245431Sdim u_int32 fpi, 15245431Sdim u_int32 fpv, 16252723Sdim int neg, 17252723Sdim short ndec, 18252723Sdim int msec 19252723Sdim ) 20252723Sdim{ 21252723Sdim u_char *cp, *cpend, *cpdec; 22210299Sed int dec; 23198090Srdivacky u_char cbuf[24]; 24198090Srdivacky char *buf, *bp; 25193323Sed 26193323Sed /* 27193323Sed * Get a string buffer before starting 28193323Sed */ 29193323Sed LIB_GETBUF(buf); 30226890Sdim 31193323Sed /* 32224145Sdim * Zero the character buffer 33193323Sed */ 34193323Sed ZERO(cbuf); 35193323Sed 36193323Sed /* 37193323Sed * Work on the integral part. This should work reasonable on 38193323Sed * all machines with 32 bit arithmetic. Please note that 32 bits 39193323Sed * can *always* be represented with at most 10 decimal digits, 40193323Sed * including a possible rounding from the fractional part. 41193323Sed */ 42193323Sed cp = cpend = cpdec = &cbuf[10]; 43193323Sed for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { 44193323Sed /* can add another digit */ 45198090Srdivacky u_int32 digit; 46193323Sed 47193323Sed digit = fpi; 48193323Sed fpi /= 10U; 49198090Srdivacky digit -= (fpi << 3) + (fpi << 1); /* i*10 */ 50193323Sed *--cp = (u_char)digit; 51193323Sed } 52193323Sed 53193323Sed /* 54193323Sed * Done that, now deal with the problem of the fraction. First 55193323Sed * determine the number of decimal places. 56193323Sed */ 57193323Sed dec = ndec; 58193323Sed if (dec < 0) 59193323Sed dec = 0; 60193323Sed if (msec) { 61193323Sed dec += 3; 62193323Sed cpdec += 3; 63193323Sed } 64193323Sed if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) 65193323Sed dec = (int)(sizeof(cbuf) - (cpend - cbuf)); 66193323Sed 67226890Sdim /* 68195098Sed * If there's a fraction to deal with, do so. 69195098Sed */ 70195098Sed for (/*NOP*/; dec > 0 && fpv != 0; dec--) { 71195098Sed u_int32 digit, tmph, tmpl; 72224145Sdim 73195098Sed /* 74195098Sed * The scheme here is to multiply the fraction 75195098Sed * (0.1234...) by ten. This moves a junk of BCD into 76195098Sed * the units part. record that and iterate. 77193323Sed * multiply by shift/add in two dwords. 78193323Sed */ 79193323Sed digit = 0; 80224145Sdim M_LSHIFT(digit, fpv); 81193323Sed tmph = digit; 82193323Sed tmpl = fpv; 83193323Sed M_LSHIFT(digit, fpv); 84193323Sed M_LSHIFT(digit, fpv); 85193323Sed M_ADD(digit, fpv, tmph, tmpl); 86193323Sed *cpend++ = (u_char)digit; 87208599Srdivacky } 88218893Sdim 89218893Sdim /* decide whether to round or simply extend by zeros */ 90218893Sdim if (dec > 0) { 91218893Sdim /* only '0' digits left -- just reposition end */ 92218893Sdim cpend += dec; 93208599Srdivacky } else { 94208599Srdivacky /* some bits remain in 'fpv'; do round */ 95193323Sed u_char *tp = cpend; 96198090Srdivacky int carry = ((fpv & 0x80000000) != 0); 97193323Sed 98193323Sed for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { 99193323Sed *--tp += 1; 100193323Sed if (*tp == 10) 101193323Sed *tp = 0; 102193323Sed else 103198090Srdivacky carry = FALSE; 104193323Sed } 105193323Sed 106193323Sed if (tp < cp) /* rounding from 999 to 1000 or similiar? */ 107198090Srdivacky cp = tp; 108193323Sed } 109193323Sed 110193323Sed /* 111198090Srdivacky * We've now got the fraction in cbuf[], with cp pointing at 112193323Sed * the first character, cpend pointing past the last, and 113193323Sed * cpdec pointing at the first character past the decimal. 114198090Srdivacky * Remove leading zeros, then format the number into the 115198090Srdivacky * buffer. 116198090Srdivacky */ 117198090Srdivacky while (cp < cpdec && *cp == 0) 118198090Srdivacky cp++; 119193323Sed if (cp >= cpdec) 120193323Sed cp = cpdec - 1; 121198090Srdivacky 122198090Srdivacky bp = buf; 123198090Srdivacky if (neg) 124198090Srdivacky *bp++ = '-'; 125198090Srdivacky while (cp < cpend) { 126193323Sed if (cp == cpdec) 127193323Sed *bp++ = '.'; 128198090Srdivacky *bp++ = (char)(*cp++) + '0'; 129198090Srdivacky } 130198090Srdivacky *bp = '\0'; 131198090Srdivacky 132198090Srdivacky /* 133193323Sed * Done! 134193323Sed */ 135193323Sed return buf; 136193323Sed} 137193323Sed 138193323Sed 139193323Sedchar * 140193323Sedmfptoa( 141193323Sed u_int32 fpi, 142193323Sed u_int32 fpf, 143193323Sed short ndec 144193323Sed ) 145193323Sed{ 146193323Sed int isneg; 147193323Sed 148193323Sed isneg = M_ISNEG(fpi); 149193323Sed if (isneg) { 150193323Sed M_NEG(fpi, fpf); 151193323Sed } 152193323Sed 153193323Sed return dolfptoa(fpi, fpf, isneg, ndec, FALSE); 154193323Sed} 155193323Sed 156193323Sed 157193323Sedchar * 158193323Sedmfptoms( 159193323Sed u_int32 fpi, 160193323Sed u_int32 fpf, 161193323Sed short ndec 162193323Sed ) 163193323Sed{ 164193323Sed int isneg; 165193323Sed 166198090Srdivacky isneg = M_ISNEG(fpi); 167203954Srdivacky if (isneg) { 168193323Sed M_NEG(fpi, fpf); 169193323Sed } 170193323Sed 171193323Sed return dolfptoa(fpi, fpf, isneg, ndec, TRUE); 172193323Sed} 173193323Sed 174198090Srdivacky 175193323Sed