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