diff options
author | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
commit | 2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch) | |
tree | b0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/libntp/dolfptoa.c | |
parent | a0741a75537b2e0514472ac3b28afc55a7846c30 (diff) | |
download | FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.zip FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.tar.gz |
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435:
ntp 4.2.8p3.
Relnotes: yes
Approved by: re (?)
Diffstat (limited to 'contrib/ntp/libntp/dolfptoa.c')
-rw-r--r-- | contrib/ntp/libntp/dolfptoa.c | 207 |
1 files changed, 104 insertions, 103 deletions
diff --git a/contrib/ntp/libntp/dolfptoa.c b/contrib/ntp/libntp/dolfptoa.c index f68679c..07ead95 100644 --- a/contrib/ntp/libntp/dolfptoa.c +++ b/contrib/ntp/libntp/dolfptoa.c @@ -1,6 +1,7 @@ /* * dolfptoa - do the grunge work of converting an l_fp number to decimal */ +#include <config.h> #include <stdio.h> #include "ntp_fp.h" @@ -10,20 +11,17 @@ char * dolfptoa( - u_long fpi, - u_long fpv, + u_int32 fpi, + u_int32 fpv, int neg, short ndec, int msec ) { - register u_char *cp, *cpend; - register u_long lwork; - register int dec; + u_char *cp, *cpend, *cpdec; + int dec; u_char cbuf[24]; - u_char *cpdec; - char *buf; - char *bp; + char *buf, *bp; /* * Get a string buffer before starting @@ -33,113 +31,81 @@ dolfptoa( /* * Zero the character buffer */ - memset((char *) cbuf, 0, sizeof(cbuf)); + ZERO(cbuf); /* - * safeguard against sign extensions and other mishaps on 64 bit platforms - * the code following is designed for and only for 32-bit inputs and - * only 32-bit worth of input are supplied. - */ - fpi &= 0xffffffff; - fpv &= 0xffffffff; - - /* - * Work on the integral part. This is biased by what I know - * compiles fairly well for a 68000. + * Work on the integral part. This should work reasonable on + * all machines with 32 bit arithmetic. Please note that 32 bits + * can *always* be represented with at most 10 decimal digits, + * including a possible rounding from the fractional part. */ - cp = cpend = &cbuf[10]; - lwork = fpi; - if (lwork & 0xffff0000) { - register u_long lten = 10; - register u_long ltmp; - - do { - ltmp = lwork; - lwork /= lten; - ltmp -= (lwork << 3) + (lwork << 1); - if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ - *--cp = (u_char)ltmp; - } while (lwork & 0xffff0000); - } - if (lwork != 0) { - register u_short sten = 10; - register u_short stmp; - register u_short swork = (u_short)lwork; - - do { - stmp = swork; - swork = (u_short) (swork/sten); - stmp = (u_short)(stmp - ((swork<<3) + (swork<<1))); - if (cp < cbuf) abort(); /* rather die a horrible death than trash the memory */ - *--cp = (u_char)stmp; - } while (swork != 0); + cp = cpend = cpdec = &cbuf[10]; + for (dec = cp - cbuf; dec > 0 && fpi != 0; dec--) { + /* can add another digit */ + u_int32 digit; + + digit = fpi; + fpi /= 10U; + digit -= (fpi << 3) + (fpi << 1); /* i*10 */ + *--cp = (u_char)digit; } /* * Done that, now deal with the problem of the fraction. First * determine the number of decimal places. */ + dec = ndec; + if (dec < 0) + dec = 0; if (msec) { - dec = ndec + 3; - if (dec < 3) - dec = 3; - cpdec = &cbuf[13]; - } else { - dec = ndec; - if (dec < 0) - dec = 0; - cpdec = &cbuf[10]; + dec += 3; + cpdec += 3; } - if (dec > 12) - dec = 12; + if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) + dec = sizeof(cbuf) - (cpend - cbuf); /* * If there's a fraction to deal with, do so. */ - if (fpv != 0) { - l_fp work; - - work.l_ui = 0; - work.l_uf = fpv; - while (dec > 0) { - l_fp ftmp; - - dec--; - /* - * The scheme here is to multiply the - * fraction (0.1234...) by ten. This moves - * a junk of BCD into the units part. - * record that and iterate. - */ - work.l_ui = 0; - L_LSHIFT(&work); - ftmp = work; - L_LSHIFT(&work); - L_LSHIFT(&work); - L_ADD(&work, &ftmp); - *cpend++ = (u_char)work.l_ui; - if (work.l_uf == 0) - break; - if (cpend > (cbuf + sizeof(cbuf))) abort(); /* rather die a horrible death than trash the memory */ - } - + for (/*NOP*/; dec > 0 && fpv != 0; dec--) { + u_int32 digit, tmph, tmpl; + /* - * Rounding is rotten + * The scheme here is to multiply the fraction + * (0.1234...) by ten. This moves a junk of BCD into + * the units part. record that and iterate. + * multiply by shift/add in two dwords. */ - if (work.l_uf & 0x80000000) { - register u_char *tp = cpend; + digit = 0; + M_LSHIFT(digit, fpv); + tmph = digit; + tmpl = fpv; + M_LSHIFT(digit, fpv); + M_LSHIFT(digit, fpv); + M_ADD(digit, fpv, tmph, tmpl); + *cpend++ = (u_char)digit; + } + + /* decide whether to round or simply extend by zeros */ + if (dec > 0) { + /* only '0' digits left -- just reposition end */ + cpend += dec; + } else { + /* some bits remain in 'fpv'; do round */ + u_char *tp = cpend; + int carry = ((fpv & 0x80000000) != 0); - *(--tp) += 1; - while (*tp >= 10) { + for (dec = tp - cbuf; carry && dec > 0; dec--) { + *--tp += 1; + if (*tp == 10) *tp = 0; - *(--tp) += 1; - }; - if (tp < cp) - cp = tp; + else + carry = FALSE; } - } - cpend += dec; + if (tp < cp) /* rounding from 999 to 1000 or similiar? */ + cp = tp; + } /* * We've now got the fraction in cbuf[], with cp pointing at @@ -148,21 +114,18 @@ dolfptoa( * Remove leading zeros, then format the number into the * buffer. */ - while (cp < cpdec) { - if (*cp != 0) - break; + while (cp < cpdec && *cp == 0) cp++; - } - if (cp == cpdec) - --cp; + if (cp >= cpdec) + cp = cpdec - 1; bp = buf; if (neg) - *bp++ = '-'; + *bp++ = '-'; while (cp < cpend) { if (cp == cpdec) - *bp++ = '.'; - *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */ + *bp++ = '.'; + *bp++ = (char)(*cp++) + '0'; } *bp = '\0'; @@ -171,3 +134,41 @@ dolfptoa( */ return buf; } + + +char * +mfptoa( + u_int32 fpi, + u_int32 fpf, + short ndec + ) +{ + int isneg; + + isneg = M_ISNEG(fpi); + if (isneg) { + M_NEG(fpi, fpf); + } + + return dolfptoa(fpi, fpf, isneg, ndec, FALSE); +} + + +char * +mfptoms( + u_int32 fpi, + u_int32 fpf, + short ndec + ) +{ + int isneg; + + isneg = M_ISNEG(fpi); + if (isneg) { + M_NEG(fpi, fpf); + } + + return dolfptoa(fpi, fpf, isneg, ndec, TRUE); +} + + |