1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * dolfptoa - do the grunge work of converting an l_fp number to decimal 3c0b746e5SOllivier Robert */ 42b15cb3dSCy Schubert #include <config.h> 5c0b746e5SOllivier Robert #include <stdio.h> 6c0b746e5SOllivier Robert 7c0b746e5SOllivier Robert #include "ntp_fp.h" 8c0b746e5SOllivier Robert #include "ntp_stdlib.h" 9c0b746e5SOllivier Robert 10c0b746e5SOllivier Robert char * 11c0b746e5SOllivier Robert dolfptoa( 122b15cb3dSCy Schubert u_int32 fpi, 132b15cb3dSCy Schubert u_int32 fpv, 14*2d4e511cSCy Schubert char sign, 159c2daa00SOllivier Robert short ndec, 16c0b746e5SOllivier Robert int msec 17c0b746e5SOllivier Robert ) 18c0b746e5SOllivier Robert { 192b15cb3dSCy Schubert u_char *cp, *cpend, *cpdec; 202b15cb3dSCy Schubert int dec; 21c0b746e5SOllivier Robert u_char cbuf[24]; 222b15cb3dSCy Schubert char *buf, *bp; 23c0b746e5SOllivier Robert 24c0b746e5SOllivier Robert /* 25c0b746e5SOllivier Robert * Get a string buffer before starting 26c0b746e5SOllivier Robert */ 27c0b746e5SOllivier Robert LIB_GETBUF(buf); 28c0b746e5SOllivier Robert 29c0b746e5SOllivier Robert /* 30c0b746e5SOllivier Robert * Zero the character buffer 31c0b746e5SOllivier Robert */ 322b15cb3dSCy Schubert ZERO(cbuf); 33c0b746e5SOllivier Robert 34c0b746e5SOllivier Robert /* 352b15cb3dSCy Schubert * Work on the integral part. This should work reasonable on 362b15cb3dSCy Schubert * all machines with 32 bit arithmetic. Please note that 32 bits 372b15cb3dSCy Schubert * can *always* be represented with at most 10 decimal digits, 382b15cb3dSCy Schubert * including a possible rounding from the fractional part. 39ea906c41SOllivier Robert */ 402b15cb3dSCy Schubert cp = cpend = cpdec = &cbuf[10]; 413311ff84SXin LI for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { 422b15cb3dSCy Schubert /* can add another digit */ 432b15cb3dSCy Schubert u_int32 digit; 44ea906c41SOllivier Robert 452b15cb3dSCy Schubert digit = fpi; 462b15cb3dSCy Schubert fpi /= 10U; 472b15cb3dSCy Schubert digit -= (fpi << 3) + (fpi << 1); /* i*10 */ 482b15cb3dSCy Schubert *--cp = (u_char)digit; 49c0b746e5SOllivier Robert } 50c0b746e5SOllivier Robert 51c0b746e5SOllivier Robert /* 52c0b746e5SOllivier Robert * Done that, now deal with the problem of the fraction. First 53c0b746e5SOllivier Robert * determine the number of decimal places. 54c0b746e5SOllivier Robert */ 55c0b746e5SOllivier Robert dec = ndec; 56c0b746e5SOllivier Robert if (dec < 0) 57c0b746e5SOllivier Robert dec = 0; 582b15cb3dSCy Schubert if (msec) { 592b15cb3dSCy Schubert dec += 3; 602b15cb3dSCy Schubert cpdec += 3; 61c0b746e5SOllivier Robert } 622b15cb3dSCy Schubert if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) 633311ff84SXin LI dec = (int)(sizeof(cbuf) - (cpend - cbuf)); 64c0b746e5SOllivier Robert 65c0b746e5SOllivier Robert /* 66c0b746e5SOllivier Robert * If there's a fraction to deal with, do so. 67c0b746e5SOllivier Robert */ 682b15cb3dSCy Schubert for (/*NOP*/; dec > 0 && fpv != 0; dec--) { 692b15cb3dSCy Schubert u_int32 digit, tmph, tmpl; 70c0b746e5SOllivier Robert 71c0b746e5SOllivier Robert /* 722b15cb3dSCy Schubert * The scheme here is to multiply the fraction 732b15cb3dSCy Schubert * (0.1234...) by ten. This moves a junk of BCD into 742b15cb3dSCy Schubert * the units part. record that and iterate. 752b15cb3dSCy Schubert * multiply by shift/add in two dwords. 76c0b746e5SOllivier Robert */ 772b15cb3dSCy Schubert digit = 0; 782b15cb3dSCy Schubert M_LSHIFT(digit, fpv); 792b15cb3dSCy Schubert tmph = digit; 802b15cb3dSCy Schubert tmpl = fpv; 812b15cb3dSCy Schubert M_LSHIFT(digit, fpv); 822b15cb3dSCy Schubert M_LSHIFT(digit, fpv); 832b15cb3dSCy Schubert M_ADD(digit, fpv, tmph, tmpl); 842b15cb3dSCy Schubert *cpend++ = (u_char)digit; 85c0b746e5SOllivier Robert } 86c0b746e5SOllivier Robert 872b15cb3dSCy Schubert /* decide whether to round or simply extend by zeros */ 882b15cb3dSCy Schubert if (dec > 0) { 892b15cb3dSCy Schubert /* only '0' digits left -- just reposition end */ 902b15cb3dSCy Schubert cpend += dec; 912b15cb3dSCy Schubert } else { 922b15cb3dSCy Schubert /* some bits remain in 'fpv'; do round */ 932b15cb3dSCy Schubert u_char *tp = cpend; 942b15cb3dSCy Schubert int carry = ((fpv & 0x80000000) != 0); 95c0b746e5SOllivier Robert 963311ff84SXin LI for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { 972b15cb3dSCy Schubert *--tp += 1; 982b15cb3dSCy Schubert if (*tp == 10) 99c0b746e5SOllivier Robert *tp = 0; 1002b15cb3dSCy Schubert else 1012b15cb3dSCy Schubert carry = FALSE; 1022b15cb3dSCy Schubert } 1032b15cb3dSCy Schubert 1042b15cb3dSCy Schubert if (tp < cp) /* rounding from 999 to 1000 or similiar? */ 105c0b746e5SOllivier Robert cp = tp; 106c0b746e5SOllivier Robert } 107c0b746e5SOllivier Robert 108c0b746e5SOllivier Robert /* 109c0b746e5SOllivier Robert * We've now got the fraction in cbuf[], with cp pointing at 110c0b746e5SOllivier Robert * the first character, cpend pointing past the last, and 111c0b746e5SOllivier Robert * cpdec pointing at the first character past the decimal. 112c0b746e5SOllivier Robert * Remove leading zeros, then format the number into the 113c0b746e5SOllivier Robert * buffer. 114c0b746e5SOllivier Robert */ 1152b15cb3dSCy Schubert while (cp < cpdec && *cp == 0) 116c0b746e5SOllivier Robert cp++; 1172b15cb3dSCy Schubert if (cp >= cpdec) 1182b15cb3dSCy Schubert cp = cpdec - 1; 119c0b746e5SOllivier Robert 120c0b746e5SOllivier Robert bp = buf; 121*2d4e511cSCy Schubert if (sign) 122*2d4e511cSCy Schubert *bp++ = sign; 123c0b746e5SOllivier Robert while (cp < cpend) { 124c0b746e5SOllivier Robert if (cp == cpdec) 125c0b746e5SOllivier Robert *bp++ = '.'; 1262b15cb3dSCy Schubert *bp++ = (char)(*cp++) + '0'; 127c0b746e5SOllivier Robert } 128c0b746e5SOllivier Robert *bp = '\0'; 129c0b746e5SOllivier Robert 130c0b746e5SOllivier Robert /* 131c0b746e5SOllivier Robert * Done! 132c0b746e5SOllivier Robert */ 133c0b746e5SOllivier Robert return buf; 134c0b746e5SOllivier Robert } 1352b15cb3dSCy Schubert 1362b15cb3dSCy Schubert 1372b15cb3dSCy Schubert char * 1382b15cb3dSCy Schubert mfptoa( 1392b15cb3dSCy Schubert u_int32 fpi, 1402b15cb3dSCy Schubert u_int32 fpf, 1412b15cb3dSCy Schubert short ndec 1422b15cb3dSCy Schubert ) 1432b15cb3dSCy Schubert { 1442b15cb3dSCy Schubert int isneg; 1452b15cb3dSCy Schubert 1462b15cb3dSCy Schubert isneg = M_ISNEG(fpi); 1472b15cb3dSCy Schubert if (isneg) { 1482b15cb3dSCy Schubert M_NEG(fpi, fpf); 1492b15cb3dSCy Schubert } 1502b15cb3dSCy Schubert 151*2d4e511cSCy Schubert return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE); 1522b15cb3dSCy Schubert } 1532b15cb3dSCy Schubert 1542b15cb3dSCy Schubert 1552b15cb3dSCy Schubert char * 1562b15cb3dSCy Schubert mfptoms( 1572b15cb3dSCy Schubert u_int32 fpi, 1582b15cb3dSCy Schubert u_int32 fpf, 1592b15cb3dSCy Schubert short ndec 1602b15cb3dSCy Schubert ) 1612b15cb3dSCy Schubert { 1622b15cb3dSCy Schubert int isneg; 1632b15cb3dSCy Schubert 1642b15cb3dSCy Schubert isneg = M_ISNEG(fpi); 1652b15cb3dSCy Schubert if (isneg) { 1662b15cb3dSCy Schubert M_NEG(fpi, fpf); 1672b15cb3dSCy Schubert } 1682b15cb3dSCy Schubert 169*2d4e511cSCy Schubert return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE); 1702b15cb3dSCy Schubert } 1712b15cb3dSCy Schubert 1722b15cb3dSCy Schubert 173