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