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